Professional Documents
Culture Documents
Here are the features the finished theme will have: Enhanced search-engine optimization (SEO) SEO Google-supported Microformat markup - see appendix A Logical markup structure than can be adapted to ANY layout Smart default CSS layouts Dynamic Body, post and comment classes Separated trackbacks and threaded comments 2 widget areas that disappear if they are empty Full standard WordPress functionality
Notes
______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________
by Jan Zumwalt (NeatInfo.com) Wordpress Theme Reference May 15, 2012 Copyright 2005-2012
Page 2 of 109
Table of Contents
Section 1 Introduction .................................................................................................................. 9
How does WordPress work? .......................................................................................................................... 9
Page 3 of 109
Page 4 of 109
Home Page display ...................................................................................................................................... 75 Front Page display ....................................................................................................................................... 76 Single Post display ....................................................................................................................................... 76 Page display ................................................................................................................................................ 76 Category display .......................................................................................................................................... 76 Tag display .................................................................................................................................................. 76 Custom Taxonomies display ........................................................................................................................ 76 Custom Post Types display .......................................................................................................................... 76 Author display .............................................................................................................................................. 76 Date display ................................................................................................................................................. 76 Search Result display .................................................................................................................................. 77 404 (Not Found) display ............................................................................................................................... 77 Attachment display ....................................................................................................................................... 77
Page 5 of 109
Comments Disabled ..................................................................................................................................... 84 Many Trackbacks ......................................................................................................................................... 84 Pages .......................................................................................................................................................... 84 Page With Comments .................................................................................................................................. 84 Page With Comments Disabled .................................................................................................................... 84 Parent Page / Child Page 1 / Child Page 2 ................................................................................................... 85 Clearing Floats ............................................................................................................................................. 85 Misc Pages .................................................................................................................................................. 85 Search Results ............................................................................................................................................ 85 Not Found .................................................................................................................................................... 85 General ........................................................................................................................................................ 85 Menus .......................................................................................................................................................... 85 Widgets ....................................................................................................................................................... 85 Screenshot .................................................................................................................................................. 85 Anchor Text and Credit Links ....................................................................................................................... 85
Page 6 of 109
Customize admin footer message ................................................................................................................ 96 Enable HTML markup in user profiles ........................................................................................................... 96 Delay feed update after posting .................................................................................................................... 96 Add an Admin link to the WordPress All-Settings page ............................................................................... 97 Remove all nofollow attributes from comments ............................................................................................. 97 Enable easy display of your posts word count.............................................................................................. 97 Enable delete and spam links for comments ................................................................................................. 98 Disable all WordPress feeds ........................................................................................................................ 98 Customize gravatars .................................................................................................................................... 99 Disable automatic formatting OF post content .............................................................................................. 99 Escape HTML entities in comments ........................................................................................................... 100 Custom comments display callback function ............................................................................................... 100
Page 7 of 109
Miscellaneous ............................................................................................................................................ 106 Multisite functions ...................................................................................................................................... 106 Multisite Site/blog functions ........................................................................................................................ 106 Multisite API ............................................................................................................................................... 107 needed to load Multisite ............................................................................................................................. 107
Page 8 of 109
Section 1 Introduction
In just a few short lessons you will write your own powerful, up-to-date, WordPress Theme from scratch. We will also learn new techniques and understand the advantages of certain options. When we have completed, you will know everything you need to know about WordPress Theme development. You can even think of the finished Theme as your own personal website development framework for WordPress. This is an impressive accomplishment for such a short period of time. This theme is the basis for a very nice one called The Shape Theme. Download it and check it out if youd like to see what the finished code is like. Alternately, you can browse through the up-to-date source code for the entire tutorial on Google Code. HOW DOES WORDPRESS WORK? WordPress has many prebuilt code modules (called Tags) that does most of the work. We can take a simple HTML structure and use PHP to call WordPress Template Tags (code modules / functions / procedures / hooks) to fill in content. It is really that simple! Its really just a matter of getting used to seeing the WordPress Template Tags along with some PHP language statements and a few PHP loops (well cover all of this). (If you are familiar with PHP, think of WordPress as a comprehensive library of PHP procedures.) For example:
<h1><?php bloginfo('description'); ?></h1>
Page 9 of 109
WORDPRESS We also need a copy of the latest version of WordPress. If youre using XAMP follow these instruction for installing WordPress on your local test server. If youre using MAMP follow these instructions for installing WordPress on your local test server. DUMMY CONTENT Your WordPress installation is going to need some sample, or dummy, content. In your WordPress admin navigate to Tools > Import and choose WordPress from the list of options. Now we only need a WXR post data file to import. There are a couple options: The Theme Unit Test data WPCandy Sample Content Each of these test data sets has their pluses and minuses. One thing I like to do is import all the dummy content I can. Everything. That way nothing gets missed. When you think youre done your theme, use the post navigation to browse through each post. Check out the archives for the month and year and category. With robust dummy content itll be easy to see if somethings amiss. A TEXT EDITOR
Page 10 of 109
You wont need any special graphics software for creating WordPress Themes just a good text editor. For Windows, you can try Notepad++ http://notepad-plus-plus.org/. Its free and open-source. For the Mac, I recommend Text Wrangler. FIREFOX Of course, you can use any browser for web development but the one I recommend is Firefox. Especially with the following 2 add-ons that will make your life a whole lot easier when it comes to developing with WordPress. The Web Developer Add-on for Firefox adds a toolbar that gives you a whole host of options for inspecting and debugging your code, from disabling all CSS styles to validating local HTML (thats the stuff happening on the browser screen of your test server). The Firebug Add-on for Firefox is indispensable. With Firebug enabled you can click on any element in your browser window and seein a window at the bottom of the screenhow it looks in the source code and how its being affected by CSS. PHP, HTML, AND CSS TUTORIALS You will do best if you have a basic understanding of HTML PHP and CSS. I recommend reading through the HTML Dog HTML Beginner Tutorial and the HTML Dog CSS Beginner Tutorial . A nice one hour PHP tutorial is on WebMonkey.com Reading through these three tutorials is completely optional but it wont hurt and will help you grasp some basic concepts. INSTALLATION 1. Download and unzip the latest version from http://wordpress.org/download/ 2. Copy the files to appropriate document root dir such as /wordpress 3. Create a blank database for WordPress in Mysql or on your web server; i.e wp or wordpress. 4. Create a db user who has all privileges for accessing and modifying the db. i.e. wpadmin, wpuser, etc. Think of a password for the db such as wppwd, wpaccess, etc. 5. Rename the wp-config-sample.php file to wp-config.php. 6. Open wp-config.php in a text editor and fill in your database details as explained in Editing wpconfig.php to generate and use your secret key password. Note that most local development AND remote servers install Mysql as localhost. 7. Upload the WordPress files in the desired location on your web server: 8. If you want to integrate WordPress into the root of your domain (e.g. http://example.com/), move or upload all contents of the unzipped WordPress directory (but excluding the directory itself) into the root directory of your web server. 9. If you want to have your WordPress installation in its own subdirectory on your web site (e.g. http://example.com/blog/), create the blog directory on your server and upload WordPress to the directory via FTP. 10. Run the WordPress installation script by accessing wp-admin/install.php in a web browser. 11. If you installed WordPress in the root directory, you should visit: http://example.com/wpadmin/install.php 12. If you installed WordPress in its own subdirectory called blog, for example, you should visit: http://example.com/blog/wp-admin/install.php
Page 11 of 109
<div id="primary" class="widget-area"> </div> <!-- #primary .widget-area --> <div id="secondary" class="widget-area"> </div> <!-- #secondary --> </div> <!-- #main -->
Page 12 of 109
<div id="footer"> <div id="colophon"> <div id="site-info"> </div> </div> </div> </div> </body> </html>
Listing 3.1
<!-- #site-info --> <!-- #colophon --> <!-- #footer --> <!-- #wrapper -->
Paste this code into your text editor and save it somewhere handy. Well be using it later when we build the file structure for our Theme. But before we do that, there are a few things well want to take a look at. UNDERSTANDING THE HTML THEME First, the class attribute on the wrapper hfeed is part of the hatom Microformat schema used by Google search engines. In plain English, this means that adding that hfeed class to our page tells any search engine that our site publishes syndicated content, like blog posts. Youll be seeing a lot of class names like this as we go along. Looking at the div structure for the header and footer, youll notice we use what is called an innerouter structure. By borrowing class names from the publishing world, Ive added some meaning to the markup in these containers. In the main area of our HTML youll notice that we have 2 widget areas that come after our content area. You will also notice our content rests inside a container div. These points are key. Search engines will see our main content come before the sidebars, but by using a CSS technique involving negative margins we can turn the format into a 1, 2, or 3 column theme with only a few lines of CSS. This HTML structure is going to future-proof your WordPress Theme and give you the opportunity to do powerful stuff with CSS. Its a good one.
Page 13 of 109
1st half 404.php attachment.php footer.php functions.php header.php index.php single.php style.css
2nd half archive.php author.php category.php comments.php page.php search.php sidebar.php tag.php
Now is a good time to create all of these files in a new Theme folder. Of course they will all have blank contents until we fill them with code. Dont let all these files scar you. Most of these files are copied with a few changes from work that we will do. It goes really quick. OK. Lets get started! Open style.css, in a text editor. We need to add some information in a comment at the top of this file. Wordpress reads and understands this. Without it, your theme wont show up in the themes panel.
/* Theme Name: Mini Theme Theme URI: http://example.com/example/ Description: A search engine optimized website framework for WordPress. Author: Your name Author URI: http://example.com/ Version: 1.0 Tags: Comma-separated tags that describe your theme. License: Like WordPress, this work is released under GNU General Public License, version 2 (GPL). License URI: http://www.gnu.org/licenses/gpl-3.0.html General comments (optional).
Page 14 of 109
*/ Listing 4.1
Some of this information is optional, all that is really needed is the Theme Name. But if you ever plan on releasing your theme, or if youre making a custom theme for someone, youll want to start out including most, if not all, of the rest. Once youve got this information in your style.css, you can activate your theme and navigate to your test site. Weve made the ultimate blank theme! You wont see anything but its there! BUILDING IN YOUR HTML STRUCTURE As mentioned before, WordPress really only needs one Theme template file index.php. We will add more template files later, but for now index.php is all we need. It is a good idea to separate our web pages into a beginning, middle, and an end. When we write templates like index.php file we usually only work on the middle and just copy the beginning and end. When its time to make a new template, we supply the middle, and copy the beginning and end. We are going to separate the html code we created in the previous section into three parts (files). header.php index.php footer.php the beginning the middle the end
Using the text editor, cut and paste the code so that the three files look like this HEADER.PHP
<html> <head> <title></title> </head> <body> <div id="wrapper" class="hfeed"> <div id="header"> <div id="masthead"> <div id="branding"> </div> <div id="access"> </div> </div> </div> <div id="main"> Listing 4.2 header.php
INDEX.PHP
<div id="container"> <div id="content"> </div>
Pg 15 of 109
33
</div>
<div id="primary" class="widget-area"> </div> <!-- #primary .widget-area --> <div id="secondary" class="widget-area"> </div> <!-- #secondary --> Listing 4.3 index.php
FOOTER.PHP
</div> <div id="footer"> <div id="colophon"> <div id="site-info"> </div><!-- #site-info --> </div> </div> </div> </body> </html> Listing 4.4 footer.php <!-- #colophon --> <!-- #footer --> <!-- #wrapper --> <!-- #main -->
Thats all that is needed to have a basic html code skeleton in our Wordpress Theme! FINISHING INDEX.PHP We need to call in the header.php and footer.php into our index.php Theme. At the top of index.php, before anything else, add the following template tag.
<?php get_header(); // include header ?> Listing 4.5
This tells Wordpress to copy the header. Alright! Can you guess what function call were going to use to copy the footer? At the bottom of index.php, after everything else add the following template tag.
<?php get_footer(); // include footer ?> Listing 4.6
Index.php is our main Template file and it adds the header and footer. If you reload you web page in Wordpress you will still see a blank page. But, if you view the browsers source code you will see the header and footer code is now included. Firefox source code - (View > Page Source). Internet Explorer source code (right click on page> select view source)
Pg 16 of 109
33
The first function tells WordPress we want to make our theme available for translation and that translation files can be found in our theme folder in a folder called languages. If youre going to create a WordPress Theme you should always try your best to make sure everything is translatable. You never know when someone else is going to need hard-coded content available in another language. WHAT IS TRANSLATABLE CODE? For foreign language translating, were going to use the php gettext functions. GetText has two functions: _e and __(two underscores). The e function is used to print simple text, and the __ function is used when the text to be displayed is already wrapped in php tags. Examples:
<?php _e("The page you're looking for doesn't exist", "Cats Who Code"); ?> <?php the_content(__('Read more...', "Cats Who Code")); ?>
Notice again the text domain name (Cats Who Code) above, remember that it should be the same as in the functions.php file.
Pg 17 of 109
33
The boring part is that you have to replace each single string by the required function. Depending on how many strings your theme have, this can take a lot of time. Some developers use GNU tools to easily extract strings from files, but as I never tried it I cant say anything about it. For those interested, take a look at google xgettext. In our next function, get_the_page_number(), youll see some translatable text. It looks like this:
__('Page ', 'your-theme') Listing 5.2
The text ready for translation is Page followed by the directory name of our theme; in this case, your-theme. Pretty straightforward but there are couple other ways to write translatable text. Well get to them when we come to them. Can you guess what get_page_number() is doing? If you take a look inside the function you can see that were checking with an IF statement to see if were on a paged page, you know, where you are when you click older posts. If you are, this function will print a bar separator and the current page number. THE HEAD SECTION Right now the blank WordPress Theme is technically invalid because its missing a Doctype telling the browser what type of code is in the file. Open up header.php and paste the following code there, before anything else.
<!DOCTYPE HTML> Listing 5.3 doc type
Now were going to get into the get into the <head> section of your Theme. The <head> section contains meta-information about a web page. Typically stuff like the document title seen at the top of your browser (and in search engine results), and links to style sheets and RSS feeds. Replace from the beginning of <head> to the end of </head> tag with the following code:
<head profile="http://gmpg.org/xfn/11"> <title> <?php if (is_single()) { single_post_title(); } elseif (is_home() || is_front_page()) { bloginfo('name'); print ' | '; bloginfo('description'); get_page_number(); } elseif (is_page()) { single_post_title(''); } elseif (is_search()) { bloginfo('name'); print ' | Search results for ' . wp_specialchars($s); get_page_number(); } elseif (is_404()) { bloginfo('name'); print ' | Not Found'; } else {
Pg 18 of 109
33
bloginfo('name'); wp_title('|'); get_page_number(); } ?> </title> <meta http-equiv="content-type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); // page content info ?>" /> <link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); // link to style sheet ?>" /> <?php if (is_singular()){ wp_enqueue_script('comment-reply'); } // threaded comments ?> <?php wp_head(); // allow plugins and customization ?> <link rel="alternate" type="application/rss+xml" href="<?php bloginfo('rss2_url'); // links for rss feeds ?>" title="<?php printf(__('%s latest posts', 'your-theme'), wp_specialchars(get_bloginfo('name'), 1)); ?>" /> <link rel="alternate" type="application/rss+xml" href="<?php bloginfo('comments_rss2_url'); ?>" title="<?php printf(__('%s latest comments', 'your-theme'), wp_specialchars(get_bloginfo('name'), 1)); ?>" /> <link rel="pingback" href="<?php bloginfo('pingback_url'); // links for pingbacks ?>" /> </head> Listing 5.4 page head
If all this looks like gobbledygook to you thats OK. Ill explain the main sections. XFN PROTOCOL The first line informs Wordpress that the XFN protocol for blog information is used. For now, you can ignore this (see appendix C).
<head profile="http://gmpg.org/xfn/11"> Listing 5.5 head profile
<TITLE> Next we create a search engine optimized title tag that shows only the post title on single posts and pages. And, of course, adds page numbers with get_page_number() on older post pages.
<title> <?php if (is_single()) { single_post_title(); } elseif (is_home() || is_front_page()) { bloginfo('name'); print ' | '; bloginfo('description'); get_page_number(); } elseif (is_page()) { single_post_title('');
Pg 19 of 109
33
} elseif (is_search()) { bloginfo('name'); print ' | Search results for ' . wp_specialchars($s); get_page_number(); } elseif (is_404()) { bloginfo('name'); print ' | Not Found'; } else { bloginfo('name'); wp_title('|'); get_page_number(); } ?> </title> Listing 5.5 page title
A script call so we can use threaded comments when we get to our comments section.
<?php if ( is_singular() ) wp_enqueue_script( 'comment-reply' ); // allow threaded comments ?> Listing 5.8 threaded comment support
Links for RSS Feeds (live news and information) and pingbacks. A pingback is a code module that provides notification to authors when somebody links to one of their documents. This enables authors to keep track of who is linking to, or referring to their articles. WordPress supports automatic pingbacks where all the links in a published article can be pinged when the article is published.
<link rel="alternate" type="application/rss+xml" href="<?php bloginfo('rss2_url'); // links for rss feeds ?>" title="<?php printf(__('%s latest posts', 'your-theme'), wp_specialchars(get_bloginfo('name'), 1)); ?>" /> <link rel="alternate" type="application/rss+xml" href="<?php bloginfo('comments_rss2_url'); ?>"
Pg 20 of 109
33
title="<?php printf(__('%s latest comments', 'your-theme'), wp_specialchars(get_bloginfo('name'), 1)); ?>" /> <link rel="pingback" href="<?php bloginfo('pingback_url'); // links for pingbacks ?>" /> Listing 5.10 RSS feeds and Pingbacks
Pg 21 of 109
33
We set the blog title in a regular div tag. Our blog description is set, using PHP IF statements and some WordPress conditional tags. If the page is either the home page or front page, the description gets wrapped in a very important <h1> tag. In the code above we used a WordPress Template Tag called bloginfo(). You can see were using it to get the URL of our WordPress blog, the name of our blog, and the description. It can be used to get over 20 different pieces of information about the blog. It takes that information and prints it in your template. This is an excellent example of how WordPress works; we take an HTML structure and use PHP to call WordPress Template Tags (code modules) to fill in content. It is really simple! Its just a matter of getting used to seeing the Template Tags, along with some PHP if statements and a few PHP loops (well get to those too). Move on down to the #access div. Change it to look like this. NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference Pg 22 of 109 33 May 15, 2012 Copyright 2005-2012
<div id="access"> <!-- #access --> <div class="skip-link"> <! link to skip to content --> <a href="#content" title=" <?php _e( 'Skip to content', 'your-theme' ) ?>"> <?php _e( 'Skip to content', 'your-theme' ) ?> </a> </div> <?php wp_page_menu( 'sort_column=menu_order' ); ?> <!page menu --> </div> <!-- #access --> Listing 6.1 access div
Here is what we have done. The first part adds a link that lets folks using a screen reader to skip right to the content.
<div class="skip-link"> <a href="#content" title=" <?php _e( 'Skip to content', 'your-theme' ) ?>" > <?php _e( 'Skip to content', 'your-theme' ) ?> </a> </div> Listing 6.2 skip to content
Next we added the page menu. It is just one template tag, with only one argument:
<?php wp_page_menu( 'sort_column=menu_order' ); ?> Listing 6.3 page menu
Our web site has a lot of bones but still not much flesh. If you look at it in your browser you should see something like this.
Now its time to start working on some of the content. And there is more good news. Your WordPress Theme Header Template is search engine optimized and coded up.
Pg 23 of 109
33
Section 7 index.php
index.php is the most crucial WordPress Theme Template. It serves as the default template and is used in place of any missing templates. Getting this template right, will help us breeze through the rest of our templates (except for the Comments Template). Open index.php and follow the next steps. THE LOOP The majority of work accomplished by index.php is done through the use of a PHP loop statement. Heres what it looks like.
<?php while ( have_posts() ) : the_post() ?> <?php endwhile; ?> Listing 7.1
This tells the Theme to loop through each post and do something with it. For the next examples I suggest you import or type in some sample post messages. We can test the loop by using the code below. Place it between the content div in index.php. Once we have this working, we can add more code to it. (warning: the code below causes an unformatted piled up output!)
<div id="content"> <!-- #content --> <?php while ( have_posts() ) : the_post() ?> <?php the_content(); ?> <?php endwhile; ?> </div> <!-- end #content --> listing 7.2 simple message loop
Pg 24 of 109
33
What happened? The messages are listed in a big smashed pile. So lets improve on this. Replace the code we just used with this.
<div id="content"> <!-- #content --> <ul> <?php while ( have_posts() ) : the_post() ?> <li> <?php the_excerpt(); ?> </li> <?php endwhile; ?> </ul> </div> <!-- end #content --> listing 7.3
OK! That looks a lot better. Do you see what we did? Now weve got a better looking format, and you get to see what the_content() and the_excerpt() do. Basically, you make a loop (starts with while ends with endwhile) and put some stuff in itstuff being WordPress Template Tags that pull information out of the posts were looping though, just like bloginfo() pulled information out of our WordPress settings in the last lesson. Alright, lets make a really awesome loop. Lets start with our basic, smushed up one. But well make sure its ready for the More Tag and the Next Page Tag. Well also put it in its own div and let machines know its the content of a blog post with the microformat class entry-content.
<div class="entry-content"> <?php the_content( __( 'Continue reading <span class="meta-nav">»</span>', 'yourtheme' ) ); ?> <?php wp_link_pages('before=<div class="page-link">' . __( 'Pages:', 'your-theme' ) . '&after=</div>') ?> </div><!-- .entry-content --> Listing 7.4
Pg 25 of 109
33
How about the post title? Thats pretty simple too. Well use the Template Tag the_title() to get the title of the post and wrap it in an <a> tag that links to the_permalink() (thats the permanent link to any particular post). Well also add in a title attribute and another microformat (bookmark) that tells machines (like Google) that this is the permalink to a blog post. Try putting the following just above the .entry-content div.
<h2 class="entry-title"> <a href="<?php the_permalink(); ?>" title="<?php printf( __('Permalink to %s', 'your-theme'), the_title_attribute('echo=0') ); ?> " rel="bookmark"><?php the_title(); ?> </a> </h2> listing 7.5
Now for all the extra bits that attend to any blog post: who wrote it, the time it was published, categories, tags, comments links. I like to break all this up into two sections: the meta stuff (author and entry date) which I put before the post content, and the utility stuff (categories, tags and comments link) that I put after the content. And both sections Well also put the post in its own containing div with the title. Lets take a look at the whole loop together. Ive inserted some PHP comments in here to help guide you along.
<div id="content"> <!-- #content -->
<?php /* The Loop with comments! */ ?> <?php while (have_posts()): the_post(); ?> <?php /* Create a div with a unique ID thanks to the_ID() and semantic classes with post_class() */ ?> <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <?php /* an h2 title */ ?> <h2 class="entry-title"> <a href="<?php the_permalink(); ?>" title="<?php printf(__('Permalink to %s', 'your-theme'), the_title_attribute('echo=0')); ?>" rel="bookmark"> <?php the_title(); ?> </a> </h2> <?php /* Microformatted, translatable post meta */ ?> <div class="entry-meta"> <span class="meta-prep meta-prep-author"> <?php _e('By ', 'your-theme'); ?> </span> <span class="author vcard"> <a class="url fn n" href="<?php echo get_author_link(false, $authordata>ID, $authordata->user_nicename); ?> " title="<?php printf(__('View all posts by %s', 'your-theme'), $authordata->display_name); ?>"> <?php the_author(); ?> </a> </span> <span class="meta-sep"> | </span> <span class="meta-prep meta-prep-entry-date"><?php _e('Published ', 'yourtheme'); ?></span>
Pg 26 of 109
33
<span class="entry-date"><abbr class="published" title="<?php the_time('Ym-d\TH:i:sO'); ?>"> <?php the_time(get_option('date_format')); ?></abbr> </span> <?php edit_post_link(__('Edit', 'your-theme'), "<span class=\"meta-sep\">|</span>\n\t\t\t\t\t\t<span class=\"editlink\">", "</span>\n\t\t\t\t\t"); ?> </div><!-- .entry-meta --> <?php /* The entry content */ ?> <div class="entry-content"> <?php the_content(__('Continue reading <span class="metanav">»</span>', 'your-theme')); ?> <?php wp_link_pages('before=<div class="page-link">' . __('Pages:', 'yourtheme') . '&after=</div>'); ?> </div><!-- .entry-content --> <?php /* Microformatted category and tag links along with a comments link */ ?> <div class="entry-utility"> <span class="cat-links"> <span class="entry-utility-prep entry-utility-prep-cat-links"> <?php _e('Posted in ', 'your-theme'); ?> </span> <?php echo get_the_category_list(', '); ?> </span> <span class="meta-sep"> | </span> <?php the_tags('<span class="tag-links"> <span class="entry-utility-prep entry-utility-prep-tag-links">' . __('Tagged ', 'your-theme') . '</span>', ", ", "</span>\n\t\t\t\t\t\t<span class=\"meta-sep\">|</span>\n"); ?> <span class="comments-link"> <?php comments_popup_link(__('Leave a comment', 'your-theme'), __('1 Comment', 'your-theme'), __('% Comments', 'your-theme')); ?> </span> <?php edit_post_link(__('Edit', 'your-theme'), "<span class=\"meta-sep\">|</span>\n\t\t\t\t\t\t<span class=\"editlink\">", "</span>\n\t\t\t\t\t\n"); ?> </div><!-- #entry-utility --> </div><!-- #post-<?php the_ID(); ?> --> <?php /* Close up the post div and then end the loop with endwhile */ ?> <?php endwhile; ?> </div> listing 7.6 <!-- end #content -->
Pg 27 of 109
33
A final word about listing 7.6. Please dont let the length of this code be intimidating. We dont have the space to go through each line of code, but if you took the time to look at each block of code, they each accomplish something simple. Often times it is a good idea to look at code as bricks in a building. The building may look huge like the Empire State building. But if you look closely, it is made out of many small bricks that are easily understood and work together. Some programmers refer to this type of programming as the black box approach. They rely on other programmers to work out the fine details, once it works they way they want they only concern themselves with how to implement (use) it.
Pg 28 of 109
33
Section 8 Navigation
Now we need a way to navigate back through our posts. Well do this with 2 WordPress Template Tags: next_posts_link() and previous_posts_link(). WARNING: These 2 functions work opposite of there label Ouch!!! I think the WordPress codex says it best. next posts link This creates a link to the previous posts. Yes, it says next posts, but its named that way just to confuse you. previous posts link This creates a link to the next posts. Yes, it says previous posts, but its named that way just to confuse you. Just like everything in index.php, post navigation needs to be given some careful thought when were building it for the first time because were going to wind up using it on almost every page in our blog. I like to have post navigation the first and last thing inside the content tags. It can be placed as needed for any particular situation. There may be situations you dont need it. If we need to disable it, we can add some CSS code to do this.
single #nav-above { display:none; } Listing 8.1- disabling an ID tag
That CSS will hide post navigation above the content on single posts. Well also want to hide any navigation code IF theres nothing to navigate too. That is, if, say, on a search, there are no older pages of posts, we dont want to output any navigation code at all to the browser. Well do that by wrapping our code in the following statement:
<?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ( $total_pages > 1 ) { ?> <?php } ?> Listing 8.2 no display if end of page count
What were doing is checking to see what the maximum number of pages is in any loop were going to be looking at and if the number of pages is greater than 1, well output our navigation. Alright, heres the code well need for your navigation, top and bottom, just before, and just after the loop.
<div id="content"> <?php /* Top post navigation */ global $wp_query;
Pg 29 of 109
33
$total_pages = $wp_query->max_num_pages; if ($total_pages > 1) { ?> <div id="nav-above" class="navigation"> <div class="nav-previous"> <?php next_posts_link(__('<span class="meta-nav">«</span> Older posts', 'your-theme')); ?> </div> <div class="nav-next"> <?php previous_posts_link(__('Newer posts <span class="meta-nav">»</span>', 'your-theme')); ?> </div> </div> <!-- #nav-above --> <?php } ?> listing 8.3 - top post navigation (relative to content tag) <?php /* Bottom post navigation */ ?> <?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ($total_pages > 1) { ?> <div id="nav-below" class="navigation"> <div class="nav-previous"><?php next_posts_link(__('<span class="meta-nav">«</span> Older posts', 'yourtheme')); ?> </div> <div class="nav-next"><?php previous_posts_link(__('Newer posts <span class="meta-nav">»</span>', 'your-theme')); ?> </div> </div><!-- #nav-below --> <?php } ?> </div> <! content --> listing 8.4 - bottom post navigation (relative to content tag)
One last thing and were done with index.php. Youll be itching to see what we can do with it, but for now were just going to put in the function call just before get_footer().
<?php get_sidebar(); ?> Listing 8.5
Pg 30 of 109
33
<div id="post-<?php the_ID(); ?>" <?php post_class(); ?> > </div><!-- #post-<?php the_ID(); ?> --> <div id="nav-below" class="navigation"> </div><!-- #nav-below -</div><!-- #content --> </div><!-- #container --> <?php get_sidebar(); ?> <?php get_footer(); ?> Listing 9.1
<!-- #nav bottom --> <!end #nav bottom --> <!-- end #content --> <!-- end #container -->
But there are going to be some notable differences. Starting with the_post() and comments_template(). Well be calling the_post() near the top of our page just after the opening of the content div and just before the navigation. We wont need a loop in this template as WordPress knows just what post were looking at thanks to the_permalink(). And since this is a single post, well need the comments_template(). And because well be separating our comments and trackbacks when we come to coding up comments.php, we need to call it just like so:
<?php comments_template('', true); ?> Listing 9.2
comments_template() will need to go just before the close of the #content div right after the
navigation. SINGLE POST NAVIGATION
Pg 31 of 109
33
Instead of using the poorly named next_posts_link() and previous_posts_link() well be using the mostly accurately named previous_post_link() and next_post_link(). They do just what you think they do.
<div id="nav-above" class="navigation"> <!-- #nav-above --> <div class="nav-previous"><?php previous_post_link( '%link', '<span class="metanav">«</span> %title' ) ?></div> <div class="nav-next"><?php next_post_link( '%link', '%title <span class="metanav">»</span>' ) ?></div> </div> <!-- end #nav-above --> <div id="nav-below" class="navigation"> <!-- #nav-below --> <div class="nav-previous"><?php previous_post_link( '%link', '<span class="metanav">«</span> %title' ) ?></div> <div class="nav-next"><?php next_post_link( '%link', '%title <span class="metanav">»</span>' ) ?></div> </div> <!-- end #nav-below --> Listing 9.3
SINGLE POST TITLES If you remember from our header.php lesson, we used a dynamic IF statement to clear the way for our Single post titles to take precedence on the page in the eyes of screen readers. We take advantage of this in this and all the rest of our Theme Templates by wrapping the title in and h1 tag.
<h1 class="entry-title"><?php the_title(); ?></h1> Listing 9.4
Youll notice that our post title code is a little simpler too. The benefit of not having to link to anything now. SINGLE POST ENTRY UTILITY LINKS The entry utility is complicated. Here I think youll see the benefit of getting something right once and standing on the shoulders of others. Before we take a look at the code we should think about why it is complicated. Because of the way comments work in WordPress we need to account for a few different scenarios: Open comments and trackbacks; only trackbacks open; only comments open; comments and trackbacks closed. And that means what looks like a mess of IF statements. It can be daunting. The code is commented but remember to look for the blocks of IF and ELSEIF statements and youll be fine. We also want to print a link to our permalink here for bookmarking purposes and the RSS for this particular single postuseful for tracking developing conversations.
<div class="entry-utility"> <?php printf( __( 'This entry was posted in %1$s%2$s. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>. Follow any comments here with the <a href="%5$s" title="Comments RSS to %4$s" rel="alternate" type="application/rss+xml">RSS feed for this post</a>.', 'your-theme' ), get_the_category_list(', '), get_the_tag_list( __( ' and tagged ', 'your-theme' ), ', ', '' ), get_permalink(), the_title_attribute('echo=0'), comments_rss() ) ?> <?php if ( ('open' == $post->comment_status) && ('open' == $post->ping_status) ) : // Comments and trackbacks open ?> <?php printf( __( '<a class="comment-link" href="#respond" title="Post a comment">Post a comment</a> or leave a trackback: <a class="trackback-link" href="%s"
Pg 32 of 109
33
title="Trackback URL for your post" rel="trackback">Trackback URL</a>.', 'your-theme' ), get_trackback_url() ) ?> <?php elseif ( !('open' == $post->comment_status) && ('open' == $post->ping_status) ) : // Only trackbacks open ?> <?php printf( __( 'Comments are closed, but you can leave a trackback: <a class="trackback-link" href="%s" title="Trackback URL for your post" rel="trackback">Trackback URL</a>.', 'your-theme' ), get_trackback_url() ) ?> <?php elseif ( ('open' == $post->comment_status) && !('open' == $post->ping_status) ) : // Only comments open ?> <?php _e( 'Trackbacks are closed, but you can <a class="comment-link" href="#respond" title="Post a comment">post a comment</a>.', 'your-theme' ) ?> <?php elseif ( !('open' == $post->comment_status) && !('open' == $post->ping_status) ) : // Comments and trackbacks closed ?> <?php _e( 'Both comments and trackbacks are currently closed.', 'your-theme' ) ?> <?php endif; ?> <?php edit_post_link( __( 'Edit', 'your-theme' ), "\n\t\t\t\t\t<span class=\"editlink\">", "</span>" ) ?> </div><!-- .entry-utility --> Listing 9.5
SINGLE POST CONTENT Unlike index.php, single.php content is pretty simple. Just one plain function call followed by wp_link_pages().
<?php the_content(); ?> <?php wp_link_pages('before=<div class="page-link">' . __( 'Pages:', 'your-theme' ) . '&after=</div>') ?> Listing 9.6
Pg 33 of 109
33
Since the page title is now wrapped in h1 tags that means our post title should be wrapped in h2 tags.
<h2 class="entry-title"> <?php the_title(); ?> </h2> Listing 10.2
Now, because our attachment template needs to actually show the attachment, our content needs to reflect that. And since most attachments are going to be images, well want to check for that and cover that scenario with an IF statement.
<div class="entry-content"> <div class="entry-attachment"> <?php if ( wp_attachment_is_image( $post->id ) ) : $att_image = wp_get_attachment_image_src( $post->id, "medium"); ?> <p class="attachment"> <a href="<?php echo wp_get_attachment_url($post->id); ?>" title="<?php the_title(); ?>" rel="attachment"> <img src="<?php echo $att_image[0];?>" width="<?php echo $att_image[1];?>" height="<?php echo $att_image[2];?>" class="attachment-medium" alt="<?php $post->post_excerpt; ?>" /> </a> </p> <?php else : ?> <a href="<?php echo wp_get_attachment_url($post->ID) ?>"
Pg 34 of 109
33
title="<?php echo wp_specialchars( get_the_title($post->ID), 1 ) ?>" rel="attachment"><?php echo basename($post->guid) ?> </a> <?php endif; ?> </div> <!-- end entry-attachment --> <div class="entry-caption"><?php if ( !empty($post->post_excerpt) ) the_excerpt() ?></div> <?php the_content( __( 'Continue reading <span class="meta-nav">»</span>', 'your-theme' ) ); ?> <?php wp_link_pages('before=<div class="page-link">' . __( 'Pages:', 'your-theme' ) . '&after=</div>') ?> </div><!-- .entry-content --> Listing 10.3
Delete the bottom navigation from what was once your old single.php, and youre done your attachment.php Template.
Pg 35 of 109
33
The complete 404 error template is based on the skeleton provided in the previous section. All you have to do is drop the navigation and add the message and search form content. Here is the complete template.
<?php get_header(); ?> <div id="container"> <div id="content"> <div id="post-0" class="post error404 not-found"> <h1 class="entry-title"><?php _e( 'Not Found', 'shape' ); ?></h1> <div class="entry-content"> <p> <?php _e( 'Sorry, but we were unable to find what you were looking for. Perhaps searching will help.', 'shape' ); ?> </p> <?php get_search_form(); ?> </div><!-- .entry-content --> </div><!-- #post-0 --> </div><!-- #content --> </div><!-- #container --> <?php get_sidebar(); ?>
Pg 36 of 109
33
<?php get_footer(); ?> listing 11.2 the complete server 404 error template
Copy the code from listing 11.2 into a file named 404.php and you are done!
Pg 37 of 109
33
Thats a lot of stuff going on for one template but if we take it a section at a time its pretty straightforward. CUSTOM CALLBACKS FOR COMMENTS AND TRACKBACKS WordPress has a function wp_list_comments() that conveniently spits out an ordered list of comments and trackbacks markup for the post (threaded too). Convenient if you want that, but unfortunately we dont. We want separated threaded comments and trackbacks, with our own custom markup. We need a set of custom callbacks for your list of Comments and Trackbacks. So add the following two functions to your theme functions.php file.
// Custom callback to list comments in the your-theme style function custom_comments($comment, $args, $depth) { $GLOBALS['comment'] = $comment; $GLOBALS['comment_depth'] = $depth; ?> <li id="comment-<?php comment_ID() ?>" <?php comment_class() ?>> <div class="comment-author vcard"><?php commenter_link() ?></div> <div class="comment-meta"><?php printf(__('Posted %1$s at %2$s <span class="metasep">|</span> <a href="%3$s" title="Permalink to this comment">Permalink</a>', 'yourtheme'), get_comment_date(), get_comment_time(), '#comment-' . get_comment_ID() ); edit_comment_link(__('Edit', 'your-theme'), ' <span class="meta-sep">|</span> <span class="edit-link">', '</span>'); ?></div> <?php if ($comment->comment_approved == '0') _e("\t\t\t\t\t<span class='unapproved'>Your comment is awaiting moderation.</span>\n", 'your-theme') ?> <div class="comment-content"> <?php comment_text() ?> </div> <?php // echo the comment reply link if($args['type'] == 'all' || get_comment_type() == 'comment') : comment_reply_link(array_merge($args, array(
Pg 38 of 109
33
'reply_text' => __('Reply','your-theme'), 'login_text' => __('Log in to reply.','your-theme'), 'depth' => $depth, 'before' => '<div class="comment-reply-link">', 'after' => '</div>' ))); endif; ?> <?php } // end custom_comments Listing 12.1
// Custom callback to list pings function custom_pings($comment, $args, $depth) { $GLOBALS['comment'] = $comment; ?> <li id="comment-<?php comment_ID() ?>" <?php comment_class() ?>> <div class="comment-author"><?php printf(__('By %1$s on %2$s at %3$s', 'your-theme'), get_comment_author_link(), get_comment_date(), get_comment_time() ); edit_comment_link(__('Edit', 'your-theme'), ' <span class="meta-sep">|</span> <span class="edit-link">', '</span>'); ?></div> <?php if ($comment->comment_approved == '0') _e('\t\t\t\t\t<span class="unapproved">Your trackback is awaiting moderation.</span>\n', 'your-theme') ?> <div class="comment-content"> <?php comment_text() ?> </div> <?php } // end custom_pings Listing 12.2
Those look kind of hairy dont they? But youre better off for it. Now you have access to the comments markup. I think the markup Ive got in there is pretty sweet and will let you make a lot of changes with just CSS alone, but if you do want to alter the markup, well, there it is. Well also need a special custom function that the custom_comments() is calling. This function will markup the gravatar were using so it fits into the microformat schema for hcard.
// Produces an avatar image with the hCard-compliant photo class function commenter_link() { $commenter = get_comment_author_link(); if ( ereg( '<a[^>]* class=[^>]+>', $commenter ) ) { $commenter = ereg_replace( '(<a[^>]* class=[\'"]?)', '\\1url ' , $commenter ); } else { $commenter = ereg_replace( '(<a )/', '\\1class="url "' , $commenter ); } $avatar_email = get_comment_author_email(); $avatar = str_replace( "class='avatar", "class='photo avatar", get_avatar( $avatar_email, 80 ) ); echo $avatar . ' <span class="fn n">' . $commenter . '</span>'; } // end commenter_link Listing 12.3
If you want to change the default size of your gravatar just change the 80 in get_avatar( $avatar_email, 80 ) ). The 80 is the size in pixels of your gravatar. THE COMMENTS TEMPLATE NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference May 15, 2012 Copyright 2005-2012
Pg 39 of 109
33
I havent scared you away have I? Heres the comments template with some helpful PHP comments that should guide you along in understanding whats happening.
<?php /* The Comments Template with, er, comments! */ ?> <div id="comments"> <?php /* Run some checks for bots and password protected posts */ ?> <?php $req = get_option('require_name_email'); // Checks if fields are required. if ( 'comments.php' == basename($_SERVER['SCRIPT_FILENAME']) ) die ( 'Please do not load this page directly. Thanks!' ); if ( ! empty($post->post_password) ) : if ( $_COOKIE['wp-postpass_' . COOKIEHASH] != $post->post_password ) : ?> <div class="nopassword"><?php _e('This post is password protected. Enter the password to view any comments.', 'your-theme') ?></div> </div><!-- .comments --> <?php return; endif; endif; ?> <?php /* See IF there are comments and do the comments stuff! */ ?> <?php if ( have_comments() ) : ?> <?php /* Count the number of comments and trackbacks (or pings) */ $ping_count = $comment_count = 0; foreach ( $comments as $comment ) get_comment_type() == "comment" ? ++$comment_count : ++$ping_count; ?> <?php /* IF there are comments, show the comments */ ?> <?php if ( ! empty($comments_by_type['comment']) ) : ?> <div id="comments-list" class="comments"> <h3><?php printf($comment_count > 1 ? __('<span>%d</span> Comments', 'your-theme') : __('<span>One</span> Comment', 'your-theme'), $comment_count) ?></h3> <?php /* If there are enough comments, build the comment navigation */ ?> <?php $total_pages = get_comment_pages_count(); if ( $total_pages > 1 ) : ?> <div id="comments-nav-above" class="comments-navigation"> <div class="paginated-comments-links"><?php paginate_comments_links(); ?></div> </div><!-- #comments-nav-above --> <?php endif; ?> <?php /* An ordered list of our custom comments callback, custom_comments(), in functions.php */ ?> <ol> <?php wp_list_comments('type=comment&callback=custom_comments'); ?> </ol> <?php /* If there are enough comments, build the comment navigation */ ?> <?php $total_pages = get_comment_pages_count(); if ( $total_pages > 1 ) : ?> <div id="comments-nav-below" class="comments-navigation"> <div class="paginated-comments-links"><?php paginate_comments_links(); ?></div> </div><!-- #comments-nav-below --> <?php endif; ?> </div><!-- #comments-list .comments --> <?php endif; /* if ( $comment_count ) */ ?> <?php /* If there are trackbacks(pings), show the trackbacks */ ?> <?php if ( ! empty($comments_by_type['pings']) ) : ?> <div id="trackbacks-list" class="comments"> <h3><?php printf($ping_count > 1 ? __('<span>%d</span> Trackbacks', 'your-theme') : __('<span>One</span> Trackback', 'your-theme'), $ping_count) ?></h3> <?php /* An ordered list of our custom trackbacks callback, custom_pings(), in functions.php */ ?> <ol> <?php wp_list_comments('type=pings&callback=custom_pings'); ?> </ol> </div><!-- #trackbacks-list .comments -->
Pg 40 of 109
33
<?php endif /* if ( $ping_count ) */ ?> <?php endif /* if ( $comments ) */ ?> <?php /* If comments are open, build the respond form */ ?> <?php if ( 'open' == $post->comment_status ) : ?> <div id="respond"> <h3><?php comment_form_title( __('Post a Comment', 'your-theme'), __('Post a Reply to %s', 'your-theme') ); ?></h3> <div id="cancel-comment-reply"><?php cancel_comment_reply_link() ?></div> <?php if ( get_option('comment_registration') && !$user_ID ) : ?> <p id="login-req"><?php printf(__('You must be <a href="%s" title="Log in">logged in</a> to post a comment.', 'your-theme'), get_option('siteurl') . '/wp-login.php?redirect_to=' . get_permalink() ) ?></p> <?php else : ?> <div class="formcontainer"> <form id="commentform" action="<?php echo get_option('siteurl'); ?>/wp-commentspost.php" method="post"> <?php if ( $user_ID ) : ?> <p id="login"><?php printf(__('<span class="loggedin">Logged in as <a href="%1$s" title="Logged in as %2$s">%2$s</a>.</span> <span class="logout"><a href="%3$s" title="Log out of this account">Log out?</a></span>', 'your-theme'), get_option('siteurl') . '/wp-admin/profile.php', wp_specialchars($user_identity, true), wp_logout_url(get_permalink()) ) ?></p> <?php else : ?> <p id="comment-notes"><?php _e('Your email is <em>never</em> published nor shared.', 'your-theme') ?> <?php if ($req) _e('Required fields are marked <span class="required">*</span>', 'your-theme') ?></p> <div id="form-section-author" class="form-section"> <div class="form-label"><label for="author"><?php _e('Name', 'your-theme') ?></label> <?php if ($req) _e('<span class="required">*</span>', 'your-theme') ?></div> <div class="form-input"><input id="author" name="author" type="text" value="<?php echo $comment_author ?>" size="30" maxlength="20" tabindex="3" /></div> </div><!-- #form-section-author .form-section --> <div id="form-section-email" class="form-section"> <div class="form-label"><label for="email"><?php _e('Email', 'your-theme') ?></label> <?php if ($req) _e('<span class="required">*</span>', 'your-theme') ?></div> <div class="form-input"><input id="email" name="email" type="text" value="<?php echo $comment_author_email ?>" size="30" maxlength="50" tabindex="4" /></div> </div><!-- #form-section-email .form-section --> <div id="form-section-url" class="form-section"> <div class="form-label"><label for="url"><?php _e('Website', 'your-theme') ?></label></div> <div class="form-input"><input id="url" name="url" type="text" value="<?php echo $comment_author_url ?>" size="30" maxlength="50" tabindex="5" /></div> </div><!-- #form-section-url .form-section --> <?php endif /* if ( $user_ID ) */ ?> <div id="form-section-comment" class="form-section"> <div class="form-label"><label for="comment"><?php _e('Comment', 'your-theme') ?></label></div> <div class="form-textarea"><textarea id="comment" name="comment" cols="45" rows="8" tabindex="6"></textarea></div> </div><!-- #form-section-comment .form-section --> <div id="form-allowed-tags" class="form-section"> <p><span><?php _e('You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes:', 'your-theme') ?></span> <code><?php echo allowed_tags(); ?></code></p> </div> <?php do_action('comment_form', $post->ID); ?> <div class="form-submit"><input id="submit" name="submit" type="submit" value="<?php _e('Post Comment', 'your-theme') ?>" tabindex="7" /><input type="hidden" name="comment_post_ID" value="<?php echo $id; ?>" /></div> <?php comment_id_fields(); ?> <?php /* Just end everything. We're done here. Close it up. */ ?> </form><!-- #commentform --> </div><!-- .formcontainer --> <?php endif /* if ( get_option('comment_registration') && !$user_ID ) */ ?>
Pg 41 of 109
33
</div><!-- #respond --> <?php endif /* if ( 'open' == $post->comment_status ) */ ?> </div><!-- #comments --> Listing 12.4
And thats it. Youve got a pretty sweet custom Comments Template to call your very own.
Pg 42 of 109
33
<div id="post-<?php the_ID(); ?>" <?php post_class(); ?> > </div><!-- #post-<?php the_ID(); ?> --> <div id="nav-below" class="navigation"> </div> </div> </div> <?php get_sidebar(); ?> <?php get_footer(); ?> Listing 13.1 <!-- #nav-below --> <!-- #nav-below --> <!-- #content --> <!-- #container -->
But, of course, each one is going to take its own different path. THE SEARCH TEMPLATE In search.php were going to reintroduce the loop back into our Template. This time with an IF statementin case we dont have any posts to loop through. Heres how itll work: IF we have posts, or, in other words, if there are posts that match the terms were searching for, THEN loop through them, sorta just like in index.php, but IF we dont have posts to loop through, or, if there arent any posts that match our search terms, give our searchers another chance at this searching business. In code, it would look like this:
<?php get_header(); ?> <div id="container"> <div id="content"> <!-- #container --> <!-- #content -->
<?php if ( have_posts() ) : ?> <?php while ( have_posts() ) : the_post() ?> <!-- this is our loop --> <?php endwhile; ?> <?php else : ?> <!-- here's where we'll put a search form if there're no posts --> <?php endif; ?> </div> </div> <!-- #content --> <!-- #container -->
Pg 43 of 109
33
Pretty straightforward, right? Almost. I like to keep all my index-ey Templates the same: Post Title, Meta, Content (or excerpt), Utility links. But when WordPress searches for posts it also searches through Pages, which dont need the post meta or utility links displayed. So, in our loop, were going to check and see if were dealing with a post or a page.
<?php if ( $post->post_type == 'post' ) { ?> <?php } ?> Listing 13.3
Wrap any code with that IF statement and it will only show if were dealing with a page. Now that we understand whats going on, heres what thecomplete search template will look like:
<?php if (have_posts()): ?> <h1 class="page-title"><?php _e('Search Results for: ', 'your-theme'); ?><span><?php the_search_query(); ?></span></h1> <?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ($total_pages > 1) { ?> <div id="nav-above" class="navigation"> <div class="nav-previous"><?php next_posts_link(__('<span class="meta-nav">«</span> Older posts', 'yourtheme')); ?></div> <div class="nav-next"><?php previous_posts_link(__('Newer posts <span class="meta-nav">»</span>', 'yourtheme')); ?></div> </div><!-- #nav-above --> <?php } ?> <?php while (have_posts()): the_post(); ?> <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf(__('Permalink to %s', 'your-theme'), the_title_attribute('echo=0')); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
Pg 44 of 109
33
<?php if ($post->post_type == 'post') { ?> <div class="entry-meta"> <span class="meta-prep meta-prep-author"><?php _e('By ', 'your-theme'); ?></span> <span class="author vcard"><a class="url fn n" href="<?php echo get_author_link(false, $authordata->ID, $authordata->user_nicename); ?>" title="<?php printf(__('View all posts by %s', 'your-theme'), $authordata->display_name); ?>"><?php the_author(); ?></a></span> <span class="meta-sep"> | </span> <span class="meta-prep meta-prep-entry-date"><?php _e('Published ', 'your-theme'); ?></span> <span class="entry-date"><abbr class="published" title="<?php the_time('Y-m-d\TH:i:sO'); ?>"><?php the_time(get_option('date_format')); ?></abbr></span> <?php edit_post_link(__('Edit', 'your-theme'), "<span class=\"metasep\">|</span>\n\t\t\t\t\t\t<span class=\"edit-link\">", "</span>\n\t\t\t\t\t"); ?> </div><!-- .entry-meta --> <?php } ?> <div class="entry-summary"> <?php the_excerpt(__('Continue reading <span class="meta-nav">»</span>', 'yourtheme')); ?> <?php wp_link_pages('before=<div class="page-link">' . __('Pages:', 'your-theme') . '&after=</div>'); ?> </div><!-- .entry-summary --> <?php if ($post->post_type == 'post') { ?> <div class="entry-utility"> <span class="cat-links"><span class="entry-utility-prep entry-utility-prep-catlinks"><?php _e('Posted in ', 'your-theme'); ?></span><?php echo get_the_category_list(', '); ?></span> <span class="meta-sep"> | </span> <?php the_tags('<span class="tag-links"><span class="entry-utility-prep entry-utilityprep-tag-links">' . __('Tagged ', 'your-theme') . '</span>', ", ", "</span>\n\t\t\t\t\t\t<span class=\"meta-sep\">|</span>\n"); ?> <span class="comments-link"><?php comments_popup_link(__('Leave a comment', 'your-theme'), __('1 Comment', 'yourtheme'), __('% Comments', 'your-theme')); ?></span> <?php edit_post_link(__('Edit', 'your-theme'), "<span class=\"metasep\">|</span>\n\t\t\t\t\t\t<span class=\"edit-link\">", "</span>\n\t\t\t\t\t\n");
Pg 45 of 109
33
?> </div><!-- #entry-utility --> <?php } ?> </div><!-- #post-<?php the_ID(); ?> --> <?php endwhile; ?> <?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ($total_pages > 1) { ?> <div id="nav-below" class="navigation"> <div class="nav-previous"><?php next_posts_link(__('<span class="meta-nav">«</span> Older posts', 'yourtheme')); ?></div> <div class="nav-next"><?php previous_posts_link(__('Newer posts <span class="meta-nav">»</span>', 'yourtheme')); ?></div> </div><!-- #nav-below --> <?php } ?> <?php else: ?> <div id="post-0" class="post no-results not-found"> <h2 class="entry-title"><?php _e('Nothing Found', 'your-theme'); ?></h2> <div class="entry-content"> <p><?php _e('Sorry, but nothing matched your search criteria. Please try again with some different keywords.', 'your-theme'); ?></p> <?php get_search_form(); ?> </div><!-- .entry-content --> </div> <?php endif; ?> Listing 13.4 complete search template
Pg 46 of 109
33
<div class="entry-content"> <!-- entry-content --> <?php the_content(); ?> <?php wp_link_pages('before=<div class="page-link">' . __( 'Pages:', 'yourtheme' ) . '&after=</div>') ?> <?php edit_post_link( __( 'Edit', 'your-theme' ), '<span class="edit-link">', '</span>' ) ?> </div> </div> the_ID(); ?> --> <!-- .entry-content --> <!-- #post-<?php
<!-- Add a custom field with Name and Value of "comments" to enable comments on this page --> <?php if ( get_post_custom_values('comments') ) comments_template() ?> </div> </div> <?php get_sidebar(); ?> <?php get_footer(); ?> Listing 14.1 <!-- #content --> <!-- #container -->
Pg 47 of 109
33
<div id="post-<?php the_ID(); ?>" <?php post_class(); ?> > </div><!-- #post-<?php the_ID(); ?> --> <div id="nav-below" class="navigation"> </div><!-- #nav-below -</div><!-- #content --> </div><!-- #container --> <?php get_sidebar(); ?> <?php get_footer(); ?> Listing 15.1
<!-- #nav bottom --> <!end #nav bottom --> <!-- end #content --> <!-- end #container -->
THE ARCHIVE TEMPLATE Heres the scheme of an Archive Template: 1. 2. 3. 4. 5. Call the_post() Check to see what kind of template this is Produce an appropriate template Rewind the posts with rewind_posts() Do the usual loopy WordPress stuff
Heres the #content of your archive.php Template. Note the Conditional Tags at the top for checking to see what kind of template were in.
<?php get_header(); ?> <div id="container"> <div id="content"> <?php the_post(); ?> <?php if ( is_day() ) : ?> <h1 class="page-title"> <?php printf( __( 'Daily Archives: <span>%s</span>', 'shape' ), get_the_time(get_option('date_format')) ) ?> </h1>
Pg 48 of 109
33
<?php elseif ( is_month() ) : ?> <h1 class="page-title"> <?php printf( __( 'Monthly Archives: <span>%s</span>', 'shape' ), get_the_time('F Y') ) ?> </h1> <?php elseif ( is_year() ) : ?> <h1 class="page-title"> <?php printf( __( 'Yearly Archives: <span>%s</span>', 'shape' ), get_the_time('Y') ) ?> </h1> <?php elseif ( isset($_GET['paged']) && !empty($_GET['paged']) ) : ?> <h1 class="page-title"><?php _e( 'Blog Archives', 'shape' ) ?></h1> <?php endif; ?> <?php rewind_posts(); ?> <?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ( $total_pages > 1 ) { ?> <div id="nav-above" class="navigation"> <div class="nav-previous"> <?php next_posts_link(__( '<span class="meta-nav">«</span> Older posts', 'shape' )) ?> </div> <div class="nav-next"> <?php previous_posts_link(__( 'Newer posts <span class="metanav">»</span>', 'shape' )) ?> </div> </div><!-- #nav-above --> <?php } ?> <?php while ( have_posts() ) : the_post(); ?> <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <h2 class="entry-title"> <a href="<?php the_permalink(); ?>" title="<?php printf( __('Permalink to %s', 'shape'), the_title_attribute('echo=0') ); ?>" rel="bookmark"> <?php the_title(); ?> </a> </h2> <div class="entry-meta"> <span class="meta-prep meta-prep-author"><?php _e('By ', 'shape'); ?></span> <span class="author vcard"> <a class="url fn n" href=" <?php echo get_author_link( false, $authordata->ID, $authordata->user_nicename ); ?>" title="<?php printf( __( 'View all posts by %s', 'shape' ), $authordata->display_name ); ?>"><?php the_author(); ?> </a> </span> <span class="meta-sep"> | </span>
Pg 49 of 109
33
<span class="meta-prep meta-prep-entry-date"> <?php _e('Published ', 'shape'); ?> </span> <span class="entry-date"> <abbr class="published" title="<?php the_time('Y-m-d\TH:i:sO') ?>"> <?php the_time( get_option( 'date_format' ) ); ?> </abbr> </span> <?php edit_post_link( __( 'Edit', 'shape' ), "<span class=\"meta-sep\">|</span>\n\t\t\t\t\t\t<span class=\"edit-link\">", "</span>\n\t\t\t\t\t" ) ?> </div><!-- .entry-meta --> <div class="entry-summary"> <?php the_excerpt( __( 'Continue reading <span class="meta-nav">»</span>', 'shape' ) ); ?> </div><!-- .entry-summary --> <div class="entry-utility"> <span class="cat-links"> <span class="entry-utility-prep entry-utility-prep-cat-links"> <?php _e( 'Posted in ', 'shape' ); ?> </span> <?php echo get_the_category_list(', '); ?> </span> <span class="meta-sep"> | </span> <?php the_tags( '<span class="tag-links"> <span class="entry-utility-prep entry-utility-prep-tag-links">' . __('Tagged ', 'shape' ) . '</span>', ", ", "</span>\n\t\t\t\t\t\t<span class=\"meta-sep\">|</span>\n" ) ?> <span class="comments-link"> <?php comments_popup_link( __( 'Leave a comment', 'shape' ), __( '1 Comment', 'shape' ), __( '% Comments', 'shape' ) ) ?> </span> <?php edit_post_link( __( 'Edit', 'shape' ), "<span class=\"meta-sep\">|</span>\n\t\t\t\t\t\t<span class=\"edit-link\">", "</span>\n\t\t\t\t\t\n" ) ?> </div><!-- #entry-utility --> </div><!-- #post-<?php the_ID(); ?> --> <?php endwhile; ?> <?php global $wp_query; $total_pages = $wp_query->max_num_pages; if ( $total_pages > 1 ) { ?> <div id="nav-below" class="navigation"> <div class="nav-previous"> <?php next_posts_link(__( '<span class="meta-nav">«</span> Older posts', 'shape' )) ?> </div> <div class="nav-next"> <?php previous_posts_link(__( 'Newer posts <span class="meta-nav">»</span>',
Pg 50 of 109
33
'shape' )) ?> </div> </div><!-- #nav-below --> <?php } ?> </div><!-- #content --> </div><!-- #container --> <?php get_sidebar(); ?> <?php get_footer(); ?> Listing 15.2
Pg 51 of 109
33
Pg 52 of 109
33
Our custom function cats_meow() removes the current category from category pages. In other words, it gets rid of redundant categories in that list of categories we have just underneath the excerpt of our post. Now, back in category.php, replace the page title section with the following code:
<h1 class="page-title"> <?php _e( 'Category Archives:', 'your-theme' ) ?> <span><?php single_cat_title() ?></span></span> </h1> <?php $categorydesc = category_description(); if ( !empty($categorydesc) ) { echo apply_filters( 'archive_meta', '<div class="archive-meta">' . $categorydesc . '</div>' ); ?> Listing 17.2
Pg 53 of 109
33
Pg 54 of 109
33
And thats it! NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference May 15, 2012 Copyright 2005-2012
Pg 55 of 109
33
Pg 56 of 109
33
I know youve been waiting patiently for this one. Everybody loves the Sidebar Template. But were going to do ours a little differently than everyone else. Ours is going to be better. CUSTOM SIDEBAR FUNCTIONS First things first. With a WordPress Sidebar Template, we need to make sure its widgetized. Ours is going to have two widget areas. That way we can re-use this code for 2-column or 3-column themes (on a 2-column theme the sidebars are stacked, one on top of the other). This is pretty straightforward. In our functions.php file were going to register our widget areas with the following code.
// Register widgetized areas function theme_widgets_init() { // Area 1 register_sidebar( array ( 'name' => 'Primary Widget Area', 'id' => 'primary_widget_area', 'before_widget' => '<li id="%1$s" class="widget-container %2$s">', 'after_widget' => "</li>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); // Area 2 register_sidebar( array ( 'name' => 'Secondary Widget Area', 'id' => 'secondary_widget_area', 'before_widget' => '<li id="%1$s" class="widget-container %2$s">', 'after_widget' => "</li>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); } // end theme_widgets_init add_action( 'init', 'theme_widgets_init' ); Listing 11.1
Now weve got two widget areas: Primary Widget Area and Secondary Widget Area. Theres no point naming them Primary Sidebar or Secondary Sidebar. In some layouts they might not even be sidebarsbut theyll always be widget areas. Now, still in functions.php were going to add two more super-cool custom code snippets. Firstly, were going to pre-set our default widgets: The Search, Pages, Categories, Archives, Links and Meta Widgets. We wont be coding them in manually to sidebar.php. Well be telling WordPress to add them to our dynamic widget area in the settings (thank Ptah Dunbar for this).
$preset_widgets = array (
Pg 57 of 109
33
'primary_widget_area' => array( 'search', 'pages', 'categories', 'archives' ), 'secondary_widget_area' => array( 'links', 'meta' ) ); if ( isset( $_GET['activated'] ) ) { update_option( 'sidebars_widgets', $preset_widgets ); } // update_option( 'sidebars_widgets', NULL ); Listing 11.2
Now, in our Primary Widget Area (primary_widget_area) weve got the Search Widget, the Pages Widget, the Categories Widget, and the Archives Widget. The Secondary Widget Area (secondary_widget_area) has the Links and Meta Widgets. Theyre all loaded up there in our WordPress options, ready and waiting. Did you see // update_option( 'sidebars_widgets', NULL ); in the last line? Uncomment that line if you need to reset your widgets for any reason. As Im sure you can guess, NULL means no widgets. Now secondly, were going to create a new conditional that will check to see if there are any widgets in a given widget area. This will be incredibly useful (with props to Chaos Kaizer) when we code up our Sidebar Template.
// Check for static widgets in widget-ready areas function is_sidebar_active( $index ){ global $wp_registered_sidebars; $widgetcolums = wp_get_sidebars_widgets(); if ($widgetcolums[$index]) return true; return false; } // end is_sidebar_active Listing 11.3
Now we need to put these custom code snippets to work. CODING THE SIDEBAR TEMPLATE With our dynamic widget areas registered and pre-set widgets, our Sidebar Template is going to be one of the simplest templates youll ever see. But remember, were also going to want to wrap our sidebars in an IF statement using our new conditional is_sidebar_active(). Heres what itll look like:
<?php if ( is_sidebar_active('primary_widget_area') ) : ?> <div id="primary" class="widget-area"> <ul class="xoxo"> <?php dynamic_sidebar('primary_widget_area'); ?> </ul> </div><!-- #primary .widget-area --> <?php endif; ?> <?php if ( is_sidebar_active('secondary_widget_area') ) : ?> <div id="secondary" class="widget-area"> <ul class="xoxo"> <?php dynamic_sidebar('secondary_widget_area'); ?> </ul> </div><!-- #secondary .widget-area --> <?php endif; ?> Listing 11.4
Pg 58 of 109
33
Now if you go into the widget admin page and pull all those widgets out of any one of those widget areas the conditional statement guarding the markup will fail. Big time. And to our benefit. No widgets. No markup. Dead simple. Just the way we like things around here.
Pg 59 of 109
33
Reload, your page and check it what reset.css does in multiple browsers (if you can). Its wonderfully gross, isnt it? REBUILD CSS Our Rebuild CSS is my own personal invention adapted from an early version of the Blueprint CSS typography stylesheet and refined in the Thematic Project. What it does is swing back some vertical rhythm in our pages, but in a really smart way.
Pg 60 of 109
33
What Ive tried to do with this iteration of my typography-rebuild CSS is combine the best of both worlds for web typography: using Pixels for font height, with relative line-height for the main declaration on the body element, and Ems for all subsequent vertical margins (like for paragraphs and lists). What does this mean? Its really easy to set your font height laterwithout doing any math workand have all of your typographical elements follow suit with an appropriate vertical rhythm (the vertical space between type elements like paragraphs and lists). Using rebuild.css is also really easy. Just add the following lines immediately after your reset.css import.
/* Rebuild default browser styles */ @import url('styles/rebuild.css'); Listing 12.2
THE BASIC WORDPRESS STYLES There are some elements in WordPress that youre just going to have to style every time. What Ive done is taken those styles and put them in there own little corner called wp.css. Right now, what weve got in there are styles for floating all the imagesincluding handling captions and image galleries. And! preset styles for simple pull-quotes. All you need to do is add a class of left or right to the blockquote tag and youre ready to roll. Can you guess how were going to use wp.css?
/* Basic WordPress Styles */ @import url('styles/wp.css'); Listing 12.3
Pg 61 of 109
33
The simplest method of turning any one of these layouts into a fixed-width layout is to add a width and centering margin to the #wrapper div.
#wrapper { margin: 0 auto; width: 960px; } Listing 13.2
STYLING THE MENU If youve never taken an unordered list (thats the smart markup generated by wp_page_menu) and styled it to look like a menu before it can seem kinda weird. As a bonus, heres the CSS I use when I start out creating menus for WordPress Themes.
#access { margin: 0 0 1.5em 0; overflow: auto; } .skip-link { position:absolute; left:-9000px; } .menu ul { list-style: none; margin: 0; } .menu ul ul { display: none; } .menu li { display: inline; } .menu a { display: block; float: left; } Listing 13.3
Pg 62 of 109
33
DEFAULT TYPES
For referance, here are the five major types that WordPress uses by default.
Post
A "post" in WordPress is the main type used by the blog. Posts are normally displayed in the blog in reverse sequential order by time (newest posts first). Posts are also used for creating the feeds.
A "page" in WordPress is like a post, but it lives outside the normal time based structure of posts. They have their own URLs directly off the main site URL. They can also use special Page Templates to display them. Pages can also be organized in a hierarchical structure, with Pages being parents to other Pages. An "attachment" is a special post that holds information about files uploaded through the Media upload system. They hold all the description and name and other information about uploaded files. For images, this is also linked to metadata information about the size of the images and thumbnails generated from the images, the location of the files, and even information obtained from EXIF data embedded in the images. A "revision" is used to hold draft posts as well as any past revisions of existing posts or pages. These are basically identical to the main post/page that they are for, but have that post/page as their parent. The "nav_menu_item" type holds information about a single item in the Navigation Menu system. These are the first examples of entries in the posts table to be used for something other than an otherwise displayable content on the blog.
Page
Attachment
Revisions
Nav Menus
CUSTOM TYPES
Adding a custom type to WordPress is done via the register_post_type function. This function allows you to define the post type and how it operates within WordPress. Here's a basic example of adding a custom post type:
add_action( 'init', 'create_post_type' ); function create_post_type() { register_post_type( 'acme_product', array( 'labels' => array( 'name' => __( 'Products' ), 'singular_name' => __( 'Product' ) ), 'public' => true, 'has_archive' => true, ) ); }
Pg 63 of 109
33
This creates a post type named "Product". It has two major arguments with it. The first one is the "labels", which define the name of the type in both plural and singular forms. The second one is "public", which is a predefined flag to show the post type in the admin section and to make it show up on the main site itself, if it's queried for. There are many more parameters you can add to the register_post_type function, to do things like set up hierarchy, show the new post type in searches, change the URLs of the new posts, and to hide or show meta boxes in the post editing screen. These parameters are optional, and you can use them to configure your post type on a detailed level.
ADMIN UI
When a post type is created like this, it gets a new top level entry in the Admin section to create posts of that new type. From there, you'll have a full post editor and everything that comes along with it by default. You can customize the UI for a post type with several hooks and filters, see this Custom Post Type snippets post by Yoast for an explanation and code examples.
Pg 64 of 109
33
URLS
The new post type will also get its own special section of the site layout. In the above example, posts of this new "product" type can be displayed at http://example.com/product/%product_name% (where %product_name% is the URL-ized name of your product, i.e. http://example.com/product/foobrozinator.) You can see this link appear in the edit pages for your new type, just like other posts.
The above will result in a URL like http://example.com/products/%product_name% (see description of %product_name% above.) Note that we used a plural form here which is a format that some people prefer because it implies a more logical URL for a page that embeds a list of products, i.e. http://example.com/products/. Also note using a generic name like "products" here can potentially conflict with other plugins or themes that use the same name but most people would dislike longer and more obscure URLs like http://example.com/acme_products/foobrozinator and resolving the URL conflict between two plugins is easier simply because the URL structure is not stored persistently in each post record in the database in the same way custom post type names are stored.
TEMPLATE FILES
The theme system supports post types too. WordPress added support for single-type-template in Version 3.0 and for archive-type-template in Version 3.1. Note: In some cases the permalink structure must be updated in order for the new template files to be accessed when viewing a custom post type. To do this go to the permalink menu, change the option to a different option, save the changes, and change it back to the desired option.
SINGLE TEMPLATE
In the form of the single-type-template. In the same way that posts are shown on their own page with single.php, custom post types will use single-{posttype}.php if it's available.
Pg 65 of 109
33
So for the above example, you could create a single-acme_product.php file and the product posts would be shown using that template.
ARCHIVE TEMPLATE
In the form of the archive-type-template. In the same way that posts are shown on their own archive with archive.php, custom post types will use archive-{posttype}.php if it's available. So for the above example, you could create a archive-acme_product.php file and the product posts would be shown using that template. Note: Use the is_post_type_archive() function to check if the query shows post type archive page, and the post_type_archive_title() to echo the post type title.
This simply loops through the latest 10 product posts and displays the title and content of them.
Pg 66 of 109
33
This article will show the WordPress theme file execution hierarchy. In short, well look at which files get served up when you load a page in WordPress. You might already know that detail post is served by single.php and detail page is served by page.php, but WordPress will search for different files depending on a variety of factors, so well be looking at how this works! First thing we should establish is this: without index.php and style.css your theme is no longer a valid WordPress theme so it stands to reason that if all you have is those two files, each page will you try to load will be served up by index.php. Take a quick peek at this cheatsheet to see what Im referring to:
Notice that the flow for each page types will end up with the index.php. That is the reason why index.php is required file for the WordPress theme. If we are missing any other files in WordPress theme (for instance, if there is no search.php file included in the theme), then index.php will be served instead.
Pg 67 of 109
33
Now lets look at some details about the execution order. I am going to show you the flow in which WordPress will search for files in your active theme folder. I hope this will be useful when you create a WordPress theme from now on: I will go through each type of files one by one and will show the execution hierarchy for the same.
HOME PAGE
This is the first and most important page of any website. So WordPress has provided the scope to customize the page. Lets have a look at the file hierarchy for the home page. 1. front-page.php 2. home.php 3. index.php While serving the home page, WordPress will search for front-page.php. If that is not found, it will use home.php. If home.php exists, itll use that. If not, it will simply default to using index.php. Note: home.php always refers to the home of the default blog, which need not to be on the actual homepage. By default the blog of posts sits on the homepage, but if it doesnt, then home.php is never used on the frontpage, but on the page the blog sits on.
1. single-[post-type].php 2. single.php 3. index.php WordPress can have as many post types as we need. So this will be easier to get different design for all/some post types. By default post is the main and default post type of the WordPress. So for example, if your custom post type is product then it will be single-product.php To know more how to add new post types in WordPress you can refer to this link.
1. 2. 3. 4.
5. index.php
Just the same as with post types, we can have a different page layout using the custom page template. So WordPress first searches for the files of the selected Page template (if it exists). If none are found, it will search for the file with the slug of the current page. Basically, if the slug is aboutus, then it will search for the file page-aboutus.php in active theme folder. WordPress will search for the files with the ID just like searching for the files with slug.
CATEGORY PAGE
1. 2. 3. 4. 5.
From the above flow, you can understand that how you can have different templates used for the category page. For instance, you could have a custom page based on slug and id, and then use a default category.php file for the rest of your categories..
TAG PAGE
1. 2. 3. 4. 5.
This will be same case as the category. You can have different pages for tag slug and tag id also.
NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference May 15, 2012 Copyright 2005-2012
Pg 69 of 109
33
TAXONOMY PAGE
1. 2. 3. 4. 5.
Here goes the different file hierarchy for the taxonomy Pages.
AUTHOR PAGE
1. 2. 3. 4. 5.
Here you come to know that you can have different designs based on users also. Same as category and tags we can have different files based on slug and ID of the user.
ATTACHMENT PAGE
1. 2. 3. 4.
Here you can see that you can have different page layout for different types of attachment. These can be differentiate from the mime type of the attached file.
DATE PAGE
1. date.php 2. archive.php 3. index.php For the date specific layout we can create date.php in theme folder. Then the flow goes to archive.php and then at last index.php.
Pg 70 of 109
33
ARCHIVE PAGE
1. archive.php 2. index.php As we come downwards to the type of files, number of files are reduced in the hierarchy. So this are the basic or we can say most used files in any WordPress themes.
SEARCH PAGE
1. search.php 2. index.php You can customize your search result with the search.php first. If search.php is not available then index.php will be served.
404 PAGE
1. 404.php 2. index.php In the case of page or post not found, WordPress will search for 404.php then if not found then it will serve index.php.
theres on thing lacking in the hierarchy of WordPress in my opinion; a template for single pages of certain categories. I search and found the code to implement this:
add_filter(single_template, create_function($t, foreach( (array) get_the_category() as $cat ) { if ( file_exists(TEMPLATEPATH . /single-{$cat->category_nicename}.php) ) return TEMPLATEPATH . /single-{$cat->category_nicename }.php; } return $t; ));
CONCLUSION
You can obviously use this information in a wide range of ways to load up custom templates for various pages In many cases, even if youre using an existing theme, you can get a custom solution without modifying the existing files. You will just need to create new file and give it a new name using the information above.
Pg 71 of 109
33
Appendix A Microformat
WHAT IS MICROFORMATS Microformats are simple conventions (known as entities) used on web pages to describe a specific type of information for example, a review, an event, a product, a business, or a person. Each entity has its own properties. For example, a Person has the properties name, address, job title, company, and email address. USING MICROFORMATS WITH HTML TAGS In general, microformats use the class attribute in HTML tags (often <span> or <div>) to assign brief and descriptive names to entities and their properties. Here's an example of a short HTML block showing basic contact information for Bob Smith.
<div> <img src="www.example.com/bobsmith.jpg" /><br> <strong>Bob Smith</strong><br> Senior editor at ACME Reviews<br> 200 Main St<br> Desertville, AZ 12345<br> </div>
Listing A.1
Here is the same HTML marked up with the hCard (Person) microformat.
<div class="vcard"> <img class="photo" src="www.example.com/bobsmith.jpg" /> <strong class="fn">Bob Smith</strong> <span class="title">Senior editor</span> at <span class="org">ACME Reviews</span> <span class="adr"> <span class="street-address">200 Main St</span> <span class="locality">Desertville</span>, <span class="region">AZ</span> <span class="postal-code">12345</span> </span> </div>
Listing A.2
Here's how this sample works. In the first line, class="vcard" indicates that the HTML enclosed in the <div> describes a Person. (The microformat used to describe people is called hCard and is referred to in HTML as vcard. This isn't a typo.) The sample describes properties of the Person item, such as a photo, name, title, organization, and address. To label properties about the person described by the vcard, each element containing one of these properties (such as <span>, <img>, or <title>) is assigned a class attribute indicating a property. For example, fn describes a person's name; title describes job title. (The Help article for each information type includes a full list of recognized properties.)
Pg 72 of 109
33
Properties can contain other properties. In the example above, the property adr describes the address of the person, and includes the subproperties street-address, locality, region and postal-code).
Pg 73 of 109
33
The term template. Used when a term in a custom taxonomy is queried. author.php The author template. Used when an author is queried. date.php The date/time template. Used when a date or time is queried. Year, month, day, hour, minute, second. archive.php The archive template. Used when a category, author, or date is queried. Note that this template will be overridden by category.php, author.php, and date.php for their respective query types. search.php The search results template. Used when a search is performed. attachment.php Attachment template. Used when viewing a single attachment. image.php Image attachment template. Used when viewing a single image attachment. If not present, attachment.php will be used. 404.php The 404 Not Found template. Used when WordPress cannot find a post or page that matches the query.
Pg 74 of 109
33
THE TEMPLATE HIERARCHY IN DETAIL The following sections describe the order in which template files are being called by WordPress for each query type. HOME PAGE DISPLAY 1. home.php 2. index.php
Pg 75 of 109
33
FRONT PAGE DISPLAY 1. front-page.php - Used for both Your latest posts or A static page as set in the Front page displays section of Settings -> Reading 2. Page display rules - When Front page is set in the Front page displays section of Settings -> Reading 3. Home Page display rules - When Posts page is set in the Front page displays section of Settings -> Reading SINGLE POST DISPLAY 1. single-{post_type}.php - If the post type were product, WordPress would look for single-product.php. 2. single.php 3. index.php PAGE DISPLAY 1. custom template file - The Page Template assigned to the Page. See get_page_templates(). 2. page-{slug}.php - If the page slug is recent-news, WordPress will look to use page-recent-news.php 3. page-{id}.php - If the page ID is 6, WordPress will look to use page-6.php 4. page.php 5. index.php CATEGORY DISPLAY 1. category-{slug}.php - If the category's slug were news, WordPress would look for category-news.php 2. category-{id}.php - If the category's ID were 6, WordPress would look for category-6.php 3. category.php 4. archive.php 5. index.php TAG DISPLAY 1. tag-{slug}.php - If the tag's slug were sometag, WordPress would look for tag-sometag.php 2. tag-{id}.php - If the tag's ID were 6, WordPress would look for tag-6.php 3. tag.php 4. archive.php 5. index.php CUSTOM TAXONOMIES DISPLAY 1. taxonomy-{taxonomy}-{slug}.php - If the taxonomy were sometax, and taxonomy's slug were someterm WordPress would look for taxonomy-sometax-someterm.php. In the case of Post Formats, the taxonomy is 'post_format' and the terms are 'post-format-{format}. i.e. taxonomy-post_format-post-format-link.php 2. taxonomy-{taxonomy}.php - If the taxonomy were sometax, WordPress would look for taxonomy-sometax.php 3. taxonomy.php 4. archive.php 5. index.php CUSTOM POST TYPES DISPLAY 1. archive-{post_type}.php - If the post type were product, WordPress would look for archive-product.php. 2. archive.php 3. index.php (when displaying a single custom post type see the Single Post display section above.) AUTHOR DISPLAY 1. author-{nicename}.php - If the author's nice name were rami, WordPress would look for author-rami.php. 2. author-{id}.php - If the author's ID were 6, WordPress would look for author-6.php. 3. author.php 4. archive.php 5. index.php DATE DISPLAY 1. date.php 2. archive.php 3. index.php
Pg 76 of 109
33
SEARCH RESULT DISPLAY 1. search.php 2. index.php 404 (NOT FOUND) DISPLAY 1. 404.php 2. index.php ATTACHMENT DISPLAY 1. MIME_type.php - it can be any MIME type (image.php, video.php, application.php). For text/plain, in order: 1. text.php 2. plain.php 3. text_plain.php 2. attachment.php 3. single-attachment.php 4. single.php 5. index.php
Pg 77 of 109
33
Pg 78 of 109
33
MetaFilter gets no value since it does not represent an actual person. The others in the list are given space-separated values appropriate to the link target. Thus, since Joe is dating his sweetheart Jane (who he has, perhaps not surprisingly, also met in person) he gives the link to her the values sweetheart date met. If Joe were not as committed to Jane, and in fact dated other people from time to time, then the sweetheart value would be dropped. See http://gmpg.org/xfn/intro for more info.
Pg 79 of 109
33
WORDPRESS SETTINGS
Adjust WordPress settings as follows: 1. Settings -> General: set the Site Title to something fairly long, and set the Tagline to something even longer. These settings will facilitate testing how the Theme handles these values. 2. Settings -> Reading: set "Blog pages show at most" to 5. This setting will ensure that index/archive pagination is triggered. 3. Settings -> Discussion: enable Threaded Comments, at least 3 levels deep. This setting will facilitate testing of Theme comment list styling. 4. Settings -> Discussion: enable Break comments into pages, and set 5 comments per page. This setting will facilitate testing of Theme paginating link markup/styling. 5. Settings -> Media: ensure that no values are set for max width or height of Embedded media. This setting will facilitate testing of the Theme $content_width setting/implementation. 6. Settings -> Permalinks: ensure that a non-default permalink setting is selected, e.g. "Month and name". This setting will facilitate stepping through the Theme Unit Tests. Create at least two Custom Menus: 1. Long Menu: all included Pages 2. Short Menu: a menu of 2-3 Pages
Pg 80 of 109
33
404 PAGE
1. The 404 page displays properly 2. Some content is displayed, more than merely the basic "Error 404 - Page Not Found" message - such as some helpful text, a search form, a list of Post or Pages, etc. 3. Debugger returns no PHP errors, warnings, or notices 4. The browser reports no JavaScript errors
SCHEDULED POST
Should not be displayed by the Theme (status "scheduled", rather than "published").
DRAFT POST
Should not be displayed by the Theme (status "draft", rather than "published").
LAYOUT TEST
1. Displays properly as a "Sticky Post." 2. Page navigation links display and work properly.
READABILITY TEST
1. Displays "Read More" link properly. 2. "Read More" link works properly (links to single post at "More" tag location).
THIS POST HAS NO BODY NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference Pg 81 of 109 33 May 15, 2012 Copyright 2005-2012
(NO TITLE)
1. Lack of post title should not adversely impact layout. 2. Post permalink should be displayed. Making the post date a permalink is a great solution. See Twenty Ten for an example.
SINGLE POST
Test the following posts when viewing a single post (single.php). Each section title matches a post title in the test data.
LAYOUT TEST
1. Displays page navigation links properly. 2. Page navigation links work properly (link to correct page). 3. Post permalink links to Page 1.
PAGE 2
1. Paragraphs are styled correctly. 2. Left, Center, Right, Justify aligned paragraphs align properly.
PAGE 3
1. h1-h6 elements are styled (as appropriate). 2. blockquote, cite styled (as appropriate). Block quotes should be indented or otherwise distinct from paragraph text. If the Theme uses a background image or quote symbol, make sure displays correctly on both short and long quotes. 3. span with style and ASCII characters should display properly. 4. table, tr, th, td are styled (as appropriate). 5. dl (dt, dd), ul, ol, li styled (as appropriate). Nested lists should be indented correctly. 6. The following HTML tags should be styled appropriately to ensure semantic meaning of each tag is preserved: address, a, big, cite, code, del, em, ins, kbd, pre, q, s, strong, sub, sup, tt, var. Note: abbr and acronym require no special styling. Also, s may be address but was deprected with HTML 4 and can be left with no special styling as well. 7. div, span maintain proper block or inline display, and styled (as appropriate).
READABILITY TEST
1. The content should be generally readable. 2. Styling should not negatively impact readability: foreground/background contrast, font family, font size, line height, paragraph width, paragraph spacing.
Pg 82 of 109
33
IMAGES TEST
Page 1 1. 2. 3. 4. Page 2 1. 2. 3. 4. Page 3 Un-Captioned Image Alignment Tests Images are aligned properly: Center, Left, Right, None. Check caption styles on first image. Images should not have a border unless it's part of design. Captioned Image Alignment Tests Images are aligned properly: Center, Left, Right, None. Check caption styles on first image. Images should not have a border unless it's part of design.
1. Other Image Tests 2. Wide Image (Resized) Test Image should display properly, and should be resized as specified. Sidebar must not be pushed to the bottom of the page. 3. Wide Image (Not Resized) Test Wide image overflows properly (such as using max-width CSS rule or overflow CSS rule). Sidebar must not be pushed below content due to image overlap. 4. Thumbnails display properly. Page 4 Floats are cleared properly for floated element (thumbnail image) at the end of the Post Content
POST WITH LONG TITLE NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference May 15, 2012 Copyright 2005-2012
Pg 83 of 109
33
Long Post Title with long non-breaking string: If you say it loud enough, youll always sound precocious; Supercalifragilisticexpialidocious! 1. Test title line height 2. Look for potential overflow issues if the theme has a small title area
(NO TITLE)
1. Post displays properly. 2. A link to the singular view of the post is recommended to be displayed. Making the post date a permalink (see Twenty Ten for an example) is a great solution.
COMMENT TEST
1. 2. 3. 4. 5. 6. 7. 8. Comments are displayed correctly. Threaded comments display correctly. Comment pagination displays correctly. Author comment is styled (as appropriate). User avatars are displayed properly. Comment form displays properly for both logged in/logged out users. When logged in as admin, edit links are displayed and work correctly. HTML is displayed properly in comments, especially lists and block quotes
COMMENTS DISABLED
1. Comment form does not display. 2. "Comments are disabled" notice is displayed.
MANY TRACKBACKS
All trackbacks are displayed properly, with no overlap.
PAGES
Test the following pages (page.php) by viewing the page that matches the section titles below.
Pg 84 of 109
33
2. No "Comments Disabled" message should be displayed. 3. Layout not adversely impacted by minimal page content.
CLEARING FLOATS
The last item in this page's content is a floated image. Make sure any elements after it are clearing properly.
MISC PAGES
Tests for search.php and 404.php.
SEARCH RESULTS
1. Search results page is helpful. 2. Search query is displayed.
NOT FOUND
404 page is present, and has helpful information.
GENERAL MENUS
1. Test with a large number of categories or pages in the menu, and test with multiple levels deep in the menus. 2. If custom menus are enabled, test the layout both with custom menus enabled and with the fallback navigation menus (no custom menu enabled).
WIDGETS
1. All widgets display correctly. 2. The default WordPress widgets should work correctly in all widgetized areas. 3. If the Theme uses custom widgets, they should work correctly. (Custom widgets are programmatically added by the Theme to the list of available widgets in Appearance > Widgets.) 4. Test all available widgets in all available widgetized areas in the Theme layout. 5. Content that appears in widgetized areas by default (hard-coded into the sidebar, for example) should disappear when widgets are enabled from Appearance > Widgets.
SCREENSHOT
1. The screenshot should accurately show the Theme design. 2. Make sure it doesn't show customized header colors or an uploaded logo that wouldn't appear by default.
Pg 85 of 109
33
LISTING SPECIFIC PAGES As with many WordPress functions, the wp_list_pages function takes several parameters. For example, the include parameter allows you to list specific pages by referencing their page IDs, separated by commas (,). The following example will only list two pages (the pages have IDs of 4 and 5).
<?php wp_list_pages('include=4,5'); ?>
EXCLUDING SPECIFIC PAGES FROM A LIST You can also exclude specific pages using the exclude parameter:
<?php wp_list_pages('exclude=4,5'); ?>
SORTING PAGES As discussed earlier, the default sorting order of wp_list_pages is alphabetical. You can, however, change the order of the listing using the sort_column parameter. The sort_column parameter can have 1 of 7 values:
post_title Sort alphabetically (default value) menu_order Sort by page order post_date Sort by date of creation post_modified Sort by time last modified ID Sort by page ID post_author Sort by the page author ID post_name Sort alphabetically by post slug
Here is the code for sorting by creation date instead of the default alphabetical order:
<?php wp_list_pages('sort_column=post_date'); ?>
SPECIFYING THE DEPTH Pages can have subpages, and subpages can have subpages. What if you only wanted to list toplevel pages but exclude their subpages? Controlling the depth works great when using it to generate dropdown menus with submenus. You can use the depth parameter like so:
<?php wp_list_pages('depth=1'); ?>
Pg 86 of 109
33
ENABLING NAVIGATION MENU If youre wanting absolute control over your navigation, using WordPress 3.0s new menu function, wp_nav_menu, is the way to go. With this function, you can add categories in menus, submenus and even insert external links into navigation menus. To take advantage of the built-in navigation menu functionality, first you need to enable it in your theme. In your functions.php file located in the theme directory, youll need to add the following:
<?php add_theme_support( 'menus' ); ?>
Next, place the following code in the location where you want the menu to show on your site (this could be in your standard theme template files such as header.php or single.php):
<?php wp_nav_menu( array('menu' => '[Menu Name]' )); ?>
Replace [Menu Name] with what you want your menu to be named. Youll then need to navigate to Appearance > Menus and create your menu with the same exact name. Everything from there is simply drag and drop! SITE URL Lets say your sites URL is http://example.com. If you want to print this out in the source, you can use the url parameter.
<?php bloginfo('url'); ?>
This works great for absolute link references. For example, if you wanted to reference your logo (lets say the file name is logo.png) that is in a directory called images, you would do the following:
<img src="<?php bloginfo('url'); ?>/images/logo.png" />
If you wanted to create a link to your RSS feed, you could use the following:
<a href="<?php bloginfo('rss2_url'); ?>">Link to RSS feed</a>
POST LOOP The POST loop is not much to look at by itself, but its whats inside the loop that really matters.
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?><?php endwhile; endif; ?>
Pg 87 of 109
33
Keeping with our Featured category example above, heres how wed show the three newest posts from the Featured category:
<?php query_posts('category_name=Featured&posts_per_page=3'); ?>
ASIDE: PASSING MULTIPLE PARAMETERS INTO FUNCTIONS Notice that we passed two parameters into the query_post function. The parameters we passed were category_name and post_per_page. In functions with more than one parameter, you can pass multiple parameters all at once by separating them with an ampersand (&). You can pass as many parameters as you want. Doing so allows you to increase the specificity of your desired outputs. EXCLUDING POSTS Similar to wp_list_pages, query_posts has a way to exclude items from being displayed. To do so, you just place a minus character (-) in front of the ID of the items you want to exclude.
<?php query_posts('cat=-97,-34'); ?>
POST TITLE
<?php the_title(); ?>
POST URL
<?php the_permalink(); ?>
POST CONETENT
<?php the_content(); ?>
POST EXCERPT
<?php the_excerpt(); ?>
POST CATEGORY
<?php the_category(); ?>
WORKING WITH CUSTOM FIELDS One of the most powerful functions that WordPress has that seems to take developers a long time to learn is the use of custom fields. Custom fields allow users to add custom name/value pairs typically used for post metadata. For example, users can add a post_thumbnail_url key that has a URL value pointing to the thumbnail image.
Pg 88 of 109
33
Users can add custom fields while they are creating posts and pages in Posts > Add new or Pages > Add new.
Ive used custom fields for everything from post thumbnails and changing the background of the individual post to adding custom link and layout areas. It becomes very powerful once youve learned it properly. Getting custom fields can be done from inside or outside of the loop. If you use it outside the loop, you have to reference the ID of the post or page you want the custom field name/value pair from. THUMBNAILS - PORTFOLIO I use timthumb with custom fields for my portfolio section.
<img src="timthumb.php?src=<?php echo get_post_meta($post->ID, 'Thumbnail',true);?>&h=456&w=506&zc=1" />
THUMBNAILS - POST
add_theme_support( post-thumbnails );
CUSTOM FIELDS FOR THUMBNAILS Lets say you want to display an image thumbnail in a post. First, you must create a new post (Posts > Add new). Under the Custom Fields fieldset, type Thumbnail into the Name field and a URI for the Value field. Then publish the post. Wherever in the loop you want the URI to be displayed, simply use the echo statement to output the result of
get_post_meta (which is a function for getting custom fields).
<?php echo get_post_meta($post->ID, 'Thumbnail', true); ?>
To use get_post_meta outside the loop, change $post->ID to the ID of the post. For example, heres how to print the URI of the thumbnail image for the post with ID of 6. NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference May 15, 2012 Copyright 2005-2012
Pg 89 of 109
33
Since we want to display an image, what we actually need to do is use the echo statement inside the src attribute of an img element:
<img src="<?php echo get_post_meta(6, 'Thumbnail', true); ?>" />
This will check to see if youre using a version of WordPress that is compatible, and then enable the automatic feed links. A couple of notes: first, this method assumes that you are not manually including any feed links in your <head>. Also, seems this functionality was being integrated with add_theme_support, so keep your eyes open for that.
This code ensures that only one copy of jQuery is included, and calls it from Googles servers to save bandwidth and take advantage of any primed caches that happen to be visiting. Note that this function needs to be located before the threaded-comments function in order for it to work.
Pg 90 of 109
33
This helps keep your document <head> a little cleaner. Note that this function needs to be located after the jQuery-inclusion function in order for it to work.
'rsd_link'); 'wp_generator'); 'feed_links', 2); 'index_rel_link'); 'wlwmanifest_link'); 'feed_links_extra', 3); 'start_post_rel_link', 10, 0); 'parent_post_rel_link', 10, 0); 'adjacent_posts_rel_link', 10, 0);
A couple of notes here: first, obviously you want to replace the UA-123456-1 with your actual GA code. Second, you may want to check out the three currently available Analytics options and modify the code accordingly. Currently, this function is using the newer ga.js tracking code, but that is easily changed to either of the other methods.
Pg 91 of 109
33
Just set your preferred number of words by editing the 80 to whatever you wish.
As you can see, there are two different versions of this code, depending on your version of WordPress. We like to stay current, so we commented out the older method but left it there in case you need it. For either version of this technique, just replace the with pants on the ground or whatever happens to suit your needs.
Nothing else needs to be done for this to work just plug it in and enjoy your new jumpless functionality. Note that this is also a convenient place to customize the read more link with whatever attributes or custom text you wish.
Pg 92 of 109
33
Feel free to change the directory to whatever you desire. Also make sure that the wp_head is present within your themes header.php file.
As before, feel free to change the directory to whatever you desire. It might be best to keep your admin favicon in a separate directory than your wordpress favicon.
The key here is to make sure that the path and image names match that of your setup. Also, when creating your image, you may want to keep in mind the properties of the original: 30px length, 31px height, transparent GIF format, and header background color of #464646 (for the image matte).
This code is plug-&-play no other modifications need to be made. Note: if you only want to disable widgets on your Home page, then remove the two comment slashes (//) from the third line.
KILL THE WORDPRESS UPDATE NAG NeatInfo.com - by Jan Zumwalt Wordpress Theme Reference May 15, 2012 Copyright 2005-2012
Pg 93 of 109
33
This is one of someone favorites, but its not for everyone. In any case, you know that Please update now.. message that appears on every page in the WordPress Admin when new versions are available? This sweet little function kills it dead (or disables it, actually): // kill the admin nag if (!current_user_can('edit_users')) { add_action('init', create_function('$a', "remove_action('init', 'wp_version_check');"), 2); add_filter('pre_option_update_core', create_function('$a', "return null;")); }
Feel free to comment this one out or remove it if you rely on the Admin nag to keep you informed of changes.
Even if you arent using it, its a nice function to have around, which is why its included here for this custom functions.php template of essential functions.
Strictly plug-&-play: just use <?php get_first_category_ID(); ?> in your theme template file to access the data.
Pg 94 of 109
33
function add_post_content($content) { if(!is_feed() && !is_home()) { $content .= '<p>This article is copyright '.date('Y').' '.bloginfo('name').'</p>'; } return $content; } add_filter('the_content', 'add_post_content');
The trick here is an old one, but its extremely useful. By changing the line beginning with $content., you can add just about any content you like.
As before, you can change the added content to whatever you want by editing the $content variable. Once in place, this will append a dynamic copyright message to each post in your feed. Note: if you happen to be adding the same content to your web pages (using the previous method) and your feeds (using this method), you may combine the two functions like so: // add custom content to feeds and posts function add_custom_content($content) { if(!is_home()) { $content .= '<p>This article is copyright '.date('Y').' '.bloginfo('name').'</p>'; } return $content; } add_filter('the_excerpt_rss', 'add_custom_content'); add_filter('the_content', 'add_custom_content');
Remember that if you use this combined function that you should remove or comment out both of the individual ones to avoid duplicate output. It will be included but commented out in the complete functions.php template file.
Pg 95 of 109
33
// remove version info from head and feeds function complete_version_removal() { return ''; } add_filter('the_generator', 'complete_version_removal');
This will remove your sites version and generator information from all of your pages and feeds, making it a little bit harder for the bad guys and a little bit safer for you and your visitors.
Here, for the sake of example, we are including a link to my site, but you can customize the content with just about anything you wish.
Note: Enabling HTML may be best left to sites that have open user-registration disabled. Use with discretion.
Pg 96 of 109
33
This code quietly and automatically gives us an extra five minutes before my post is added to our feeds. If you need more or less than five minutes, just edit the $wait variable with the integer of your choice.
Having access to your All-Settings page can be extremely helpful, so its nice to display a direct link for easy access. The following slice of code in your functions.php file is all thats needed: // admin link for all settings function all_settings_link() { add_options_page(__('All Settings'), __('All Settings'), 'administrator', 'options.php'); } add_action('admin_menu', 'all_settings_link');
Once in place, you will see a link to your All Settings page in the WordPress Admin. You can change the name of the link to whatever you prefer by editing the two instances of All Settings.
That code will remove all instances of the nefarious nofollow attribute from all comment items, including the author link and comment text. This is a great way to automatically remove nofollow with no plugins or hacking required.
Pg 97 of 109
33
// count words in posts function word_count() { global $post; echo str_word_count($post->post_content); } Then, simply place this anywhere in your loop where you would like the number to appear:
So for example, you could display your posts word count to your visitors with something like: <p>This post contains a whopping <?php word_count(); ?> words.</p> We can also easily display the word count of other items, such as the post title: <?php echo str_word_count($post->post_title); ?> Likewise, we can exclude the function from functions.php and get the word count with a single line of code in the loop: <?php echo str_word_count($post->post_content); ?>
Just slap em anywhere in your post loop to display your word count. Not always needed, but nice to have available.
Pg 98 of 109
33
This function will quietly and completely disable all of your sites feeds, including all different formats. With this code in place, any request for your feed will return the following message in a nice, big set of h1 tags: Feed not available, please visit our Home Page! This message is easily customized by editing the wp_die argument in the function.
CUSTOMIZE GRAVATARS
Instead of suffering with the rather dull default gravatars, use this code to customize your own: // customize default gravatars function custom_gravatars($avatar_defaults) { // change the default gravatar $customGravatar1 = get_bloginfo('template_directory').'/images/gravatar-01.png'; $avatar_defaults[$customGravatar1] = Default; // add a custom user gravatar $customGravatar2 = get_bloginfo(template_directory)./images/gravatar-02.png; $avatar_defaults[$customGravatar2] = Custom Gravatar; // add another custom gravatar $customGravatar3 = get_bloginfo(template_directory)./images/gravatar-03.png; $avatar_defaults[$customGravatar3] = Custom gravatar; return $avatar_defaults; } add_filter(avatar_defaults, custom_gravatars);
Of course, you can manually choose a default gravatar by specifying its location via the get_avatar template tag, but this method makes it so much easier. Not only does it replace the default with multiple custom gravatars, but it also goes the extra mile by displaying them in the WordPress Admin area under Settings > Discussion. From there, you can select any of your custom gravatars by simply selecting it and clicking the Update button. Nothing could be easier. A few notes about this function: 1. As is, it adds three new gravatars to choose as defaults. 2. Each gravatar should be located in your themes images directory. 3. You can add as many default gravatars as you would like by emulating the code pattern. 4. If you keep your custom gravatars someplace else, be sure and edit the image paths accordingly.
Pg 99 of 109
33
foreach ($pieces as $piece) { if (preg_match($pattern_contents, $piece, $matches)) { $new_content .= $matches[1]; } else { $new_content .= wptexturize(wpautop($piece)); } } return $new_content; } remove_filter(the_content, wpautop); remove_filter(the_content, wptexturize); add_filter(the_content, my_formatter, 99);
With that code in place, you can insert unformatted code into your posts via the [raw] shortcode, for example: [raw]Unformatted content[/raw]
Anything contained within those shortcodes will be left unformatted when displayed in your posts.
Once in place in your functions.php file, simply tell your commentators to wrap their code snippets in <code> tags. In other words, any content wrapped in <code> tags will be encoded automatically. Plus, in order to prevent unwanted <br /> tags, this function also automatically removes line breaks after the opening <code> tag and before the closing <code> tag.
Pg 100 of 109
33
<li <?php comment_class(); ?> id=comment-<?php comment_ID(); ?>> <div class=comment-wrap> <?php echo get_avatar(get_comment_author_email(), $size = 50, $default = bloginfo(stylesheet_directory)./images/gravatar.png); ?> <div class=comment-intro> <?php printf(__(%s), get_comment_author_link()); ?> <a class=comment-permalink href=<?php echo htmlspecialchars(get_comment_link($comment>comment_ID)); ?>><?php comment_date(F j, Y); ?> @ <?php comment_time(); ?></a><?php edit_comment_link(Edit, , ); ?> </div> <?php if ($comment->comment_approved == 0) : ?> <p class=comment-moderation><?php _e(Your comment is awaiting moderation.); ?></p> <?php endif; ?> <div class=comment-text><?php comment_text(); ?></div> <div class=reply id=comment-reply-<?php comment_ID(); ?>> <?php comment_reply_link(array_merge($args, array(reply_text=>Reply, login_text=>Log in to Reply, add_below=>commentreply, depth=>$depth, max_depth=>$args['max_depth']))); ?> </div> </div> <?php } // WP adds the closing </li>
Theres a lot going on here, so lets highlight the important stuff: 1. 2. 3. Do not add the closing </li> element WordPress does this for you. This function calls for a default gravatar in your themes images directory. Either ensure youve got the required image in place or edit the code to reflect your sites reality. Once this function is included in your functions.php file, you can display it by using the following comments loop in your comments.php file: <?php if (have_comments()) : ?> <ol class="commentlist"> <?php wp_list_comments('type=comment&style=ol&callback=custom_comments_callback'); ?> </ol> <?php else : ?>
Notice the third parameter for the wp_list_comments template tag? thats what makes it go. Also important is the style=ol parameter, which tells WordPress that we are using an ordered list for comments and that it should automatically close the markup with a </li> element.
Pg 101 of 109
33
Menus
HORIZONTAL MENUS http://codex.wordpress.org/Creating_Horizontal_Menus
Okay, we can't resist. Let's take this another step further and give our new horizontal menu list some real jazz. See if you can tell what is being done to change the look.
#navmenu ul {margin: 0; padding: 0; list-style-type: none; list-style-image: none; } #navmenu li {display: inline; } #navmenu ul li a {text-decoration:none; margin: 4px; padding: 5px 20px 5px 20px; color: blue; background: pink;} #navmenu ul li a:hover {color: purple; background: yellow; }
If we did this all correctly, your list should look like this:
WITHOUT CSS
One should note that the all the above will fail in browsers with CSS turned off: the <li> lists will still be formatted vertically, not horizontally. Therefore, if one wishes to be portable to such browsers, one might use e.g.,
<p>Archives:<?php wp_get_archives('format=custom&show_post_count=1&type=yearly&after=;'); ?> Categories:<?php echo str_replace('<br />',';', wp_list_categories('style=&show_count=1&echo=0'));?></p>
Pg 102 of 109
33
Functions by category
POSTS get_adjacent_post get_boundary_post get_children get_extended get_next_post get_next_posts_link get_permalink get_the_excerpt get_the_post_thumbnail get_post get_post_ancestors get_post_mime_type get_post_status get_post_format get_edit_post_link get_delete_post_link get_previous_post previous_posts_link get_posts is_post (deprecated) is_single is_sticky the_ID the_date wp_get_recent_posts wp_get_single_post POST-CUSTOM POST TYPE register_post_type is_post_type_archive post_type_archive_title add_post_type_support remove_post_type_support post_type_supports set_post_type post_type_exists get_post_type get_post_types get_post_type_archive_link get_post_type_object get_post_type_capabilities get_post_type_labels is_post_type_hierarchical POST-POST INSERTION/REMOVAL wp_delete_post wp_insert_post wp_publish_post wp_update_post POST-PAGES get_all_page_ids get_ancestors get_page get_page_link get_page_by_path get_page_by_title get_page_children get_page_hierarchy get_page_uri get_pages is_page page_uri_index wp_list_pages wp_page_menu POST-CUSTOM FIELDS (POSTMETA) add_post_meta delete_post_meta get_post_custom get_post_custom_keys get_post_custom_values get_post_meta update_post_meta POST-ATTACHMENTS get_attached_file is_attachment is_local_attachment update_attached_file wp_attachment_is_image wp_insert_attachment wp_delete_attachment wp_get_attachment_image wp_get_attachment_link wp_get_attachment_image_src wp_get_attachment_metadata wp_get_attachment_thumb_file wp_get_attachment_thumb_url wp_get_attachment_url wp_check_for_changed_slugs wp_count_posts wp_mime_type_icon wp_generate_attachment_metadata wp_update_attachment_metadata POST-BOOKMARKS get_bookmark get_bookmarks wp_list_bookmarks POST-TERMS wp_get_post_categories wp_set_post_categories wp_get_post_tags wp_set_post_tags wp_get_post_terms wp_set_post_terms get_the_ID get_the_author get_the_content get_the_title wp_trim_excerpt CATEGORIES cat_is_ancestor_of get_all_category_ids get_ancestors get_cat_ID get_cat_name get_categories get_category get_category_by_path get_category_by_slug get_the_category_by_ID get_category_link get_category_parents get_the_category single_cat_title in_category is_category the_category wp_category_checklist wp_list_categories CATEGORY-CREATION wp_create_category wp_delete_category wp_insert_category CATEGORY-TAGS get_tag get_tag_link get_tags get_the_tag_list get_the_tags is_tag the_tags CATEGORY-TAXONOMY get_taxonomies get_term get_the_term_list get_term_by the_terms get_the_terms get_term_children get_term_link get_terms is_taxonomy (deprecated) is_taxonomy_hierarchical is_term (deprecated) taxonomy_exists term_exists register_taxonomy register_taxonomy_for_object_type
Pg 103 of 109
33
wp_get_object_terms wp_set_object_terms wp_insert_term wp_update_term wp_delete_term wp_terms_checklist ADMINS, ROLES AND CAPABILITIES add_cap add_role author_can current_user_can current_user_can_for_blog get_role get_super_admins is_super_admin map_meta_cap remove_cap remove_role user_can USERS AND AUTHORS auth_redirect count_users count_user_posts count_many_users_posts email_exists get_currentuserinfo get_current_user_id get_profile get_userdata get_userdatabylogin get_usernumposts get_users get_users_of_blog set_current_user user_pass_ok username_exists validate_username wp_get_current_user wp_set_current_user get_author_posts_url USER META add_user_meta delete_user_meta get_user_meta update_user_meta get_the_author_meta USER INSERTION/REMOVAL FILTERS has_filter add_filter apply_filters current_filter merge_filters remove_filter remove_all_filters
wp_create_user wp_delete_user wp_insert_user wp_update_user LOGIN / LOGOUT is_user_logged_in wp_login_form wp_signon wp_logout FEED FUNCTIONS bloginfo_rss comment_author_rss comment_link comment_text_rss do_feed do_feed_atom do_feed_rdf do_feed_rss do_feed_rss2 fetch_feed fetch_rss (deprecated) get_author_feed_link get_bloginfo_rss get_category_feed_link get_comment_link get_comment_author_rss get_post_comments_feed_link get_rss (deprecated) get_search_comments_feed_link get_search_feed_link get_the_category_rss get_the_title_rss permalink_single_rss post_comments_feed_link rss_enclosure the_title_rss the_category_rss the_content_rss the_excerpt_rss wp_rss (deprecated) COMMENT, PING, AND TRACKBACK FUNCTIONS add_ping add_comment_meta check_comment comment_text comment_form comments_number discover_pingback_server_uri ACTIONS has_action add_action do_action do_action_ref_array did_action remove_action remove_all_actions
delete_comment_meta do_all_pings do_enclose do_trackbacks generic_ping get_approved_comments get_avatar get_comment get_comment_text get_comment_meta get_comments wp_list_comments get_enclosed get_lastcommentmodified get_pung get_to_ping have_comments is_trackback pingback privacy_ping_filter sanitize_comment_cookies trackback trackback_url trackback_url_list update_comment_meta weblog_ping wp_allow_comment wp_count_comments wp_delete_comment wp_filter_comment wp_get_comment_status wp_get_current_commenter wp_insert_comment wp_new_comment wp_set_comment_status wp_throttle_comment_flood wp_update_comment wp_update_comment_count COMMENTS LOOP comment_class comment_ID comment_author comment_date comment_time COMMENTS PAGINATION paginate_comments_links previous_comments_link next_comments_link
Pg 104 of 109
33
unregister_setting menu_page_url SHORTCODES add_shortcode do_shortcode do_shortcode_tag get_shortcode_regex remove_shortcode remove_all_shortcodes shortcode_atts shortcode_parse_atts strip_shortcodes INCLUDE FUNCTIONS comments_template get_footer get_header get_sidebar get_search_form OTHER FUNCTIONS add_custom_background add_custom_image_header add_theme_support body_class current_theme_supports dynamic_sidebar get_404_template get_archive_template get_attachment_template get_author_template get_category_template|get_category _template get_comments_popup_template get_current_theme get_date_template get_header_image get_header_textcolor get_home_template get_locale_stylesheet_uri get_page_template get_paged_template get_query_template get_search_template get_single_template get_stylesheet get_stylesheet_directory get_stylesheet_directory_uri get_stylesheet_uri get_tag_template get_taxonomy_template get_template get_template_directory get_template_directory_uri get_template_part get_theme get_theme_data get_theme_support get_theme_mod get_theme_root
get_theme_root_uri get_themes header_image header_textcolor is_child_theme load_template locale_stylesheet locate_template post_class preview_theme preview_theme_ob_filter preview_theme_ob_filter_callback register_nav_menu register_nav_menus register_sidebar register_sidebars register_theme_directory remove_theme_mod remove_theme_mods require_if_theme_supports search_theme_directories set_theme_mod switch_theme validate_current_theme unregister_nav_menu wp_get_archives wp_get_nav_menu_items wp_nav_menu wp_page_menu wp_title FORMATTING FUNCTIONS add_magic_quotes addslashes_gpc antispambot attribute_escape backslashit balanceTags clean_pre clean_url convert_chars convert_smilies ent2ncr esc_attr esc_html esc_js esc_textarea esc_url force_balance_tags format_to_edit format_to_post funky_javascript_fix htmlentities2 is_email js_escape (deprecated) make_clickable popuplinks remove_accents sanitize_email sanitize_file_name sanitize_user sanitize_title sanitize_title_with_dashes
seems_utf8 stripslashes_deep trailingslashit untrailingslashit url_shorten utf8_uri_encode TIME/DATE FUNCTIONS current_time date_i18n get_calendar get_date_from_gmt get_lastpostdate get_lastpostmodified get_day_link get_gmt_from_date get_month_link the_time get_the_time the_modified_time get_the_modified_time get_weekstartend get_year_link human_time_diff is_new_day iso8601_timezone_to_offset iso8601_to_datetime mysql2date SERIALIZATION is_serialized is_serialized_string maybe_serialize maybe_unserialize OPTIONS add_option delete_option form_option get_alloptions get_site_option get_site_url get_user_option get_option update_option update_user_option ADMIN MENU FUNCTIONS add_menu_page remove_menu_page add_submenu_page remove_submenu_page add_object_page add_utility_page TOOLBAR FUNCTIONS add_node remove_node add_group get_node
Pg 105 of 109
33
get_nodes FORM HELPERS checked disabled selected NONCES AND REFERERS (SECURITY) check_admin_referer check_ajax_referer wp_create_nonce wp_explain_nonce wp_get_original_referer wp_get_referer wp_nonce_ays wp_nonce_field wp_nonce_url wp_original_referer_field wp_referer_field wp_verify_nonce XMLRPC xmlrpc_getpostcategory xmlrpc_getposttitle xmlrpc_removepostdata user_pass_ok LOCALIZATION __ _x _n _nx _e _ex _ngettext (deprecated) esc_attr__ esc_attr_e get_locale load_default_textdomain load_plugin_textdomain load_textdomain load_theme_textdomain CRON (SCHEDULING) spawn_cron wp_clear_scheduled_hook wp_cron wp_get_schedule wp_get_schedules wp_next_scheduled wp_reschedule_event wp_schedule_event wp_schedule_single_event wp_unschedule_event CONDITIONAL TAGS INDEX comments_open has_nav_menu
has_tag in_category is_404 is_admin is_archive is_attachment is_author is_category is_comments_popup is_date is_day is_feed is_front_page is_home is_month is_page is_page_template is_paged is_preview is_search is_single is_singular is_sticky is_tag is_tax is_time is_trackback is_year pings_open MISCELLANEOUS add_query_arg admin_url bool_from_yn cache_javascript_headers content_url do_robots get_bloginfo get_num_queries get_query_var home_url includes_url is_blog_installed is_main_site is_main_query is_ssl log_app make_url_footnote (deprecated) nocache_headers remove_query_arg site_url status_header wp wp_check_filetype wp_clearcookie wp_die wp_footer wp_get_cookie_login wp_get_http_headers wp_hash wp_head wp_mail wp_mkdir_p
wp_new_user_notification wp_notify_moderator wp_notify_postauthor wp_parse_args wp_redirect wp_reset_postdata wp_reset_query wp_remote_fopen wp_salt wp_set_auth_cookie wp_upload_bits wp_upload_dir MULTISITE FUNCTIONS admin_notice_feed avoid_blog_page_permalink_collision check_import_new_users check_upload_size choose_primary_blog confirm_delete_users dashboard_quota display_space_usage format_code_lang get_site_allowed_themes get_space_allowed get_upload_space_available grant_super_admin is_upload_space_available ms_deprecated_blogs_file mu_dropdown_languages new_user_email_admin_notice redirect_user_to_blog refresh_user_details revoke_super_admin secret_salt_warning send_confirmation_on_profile_email show_post_thumbnail_warning site_admin_notice sync_category_tag_slugs update_option_new_admin_email update_user_status upload_size_limit_filter upload_space_setting wpmu_delete_blog wpmu_delete_user wpmu_get_blog_allowedthemes _admin_notice_multisite_activate_plu gins_page MULTISITE SITE/BLOG FUNCTIONS add_blog_option delete_blog_option get_blogaddress_by_domain get_blogaddress_by_id get_blogaddress_by_name get_blog_details get_blog_option get_blog_status get_id_from_blogname get_last_updated is_archived refresh_blog_details
Pg 106 of 109
33
restore_current_blog switch_to_blog update_archived update_blog_details update_blog_option update_blog_status wpmu_update_blogs_date ms_cookie_constants ms_file_constants ms_subdomain_constants ms_upload_constants MULTISITE API add_existing_user_to_blog add_new_user_to_blog add_user_to_blog check_upload_mimes create_empty_blog domain_exists filter_SSL fix_import_form_size fix_phpmailer_messageid force_ssl_content get_active_blog_for_user get_admin_users_for_domain get_blogs_of_user get_blog_count get_blog_id_from_url get_blog_permalink get_blog_post get_current_site get_dashboard_blog get_dirsize get_most_recent_post_of_user get_sitestats get_user_count get_user_id_from_string global_terms
insert_blog install_blog install_blog_defaults is_blog_user is_email_address_unsafe is_user_member_of_blog is_user_option_local is_user_spammy maybe_add_existing_user_to_blog maybe_redirect_404 newblog_notify_siteadmin newuser_notify_siteadmin recurse_dirsize redirect_mu_dashboard redirect_this_site remove_user_from_blog signup_nonce_check signup_nonce_fields update_blog_public update_posts_count upload_is_file_too_big upload_is_user_over_quota users_can_register_signup_filter welcome_user_msg_filter wordpressmu_wp_mail_from wpmu_activate_signup wpmu_admin_redirect_add_updated _param wpmu_create_blog wpmu_create_user wpmu_log_new_registrations wpmu_signup_blog wpmu_signup_blog_notification wpmu_signup_user wpmu_signup_user_notification wpmu_validate_blog_signup wpmu_validate_user_signup wpmu_welcome_notification wpmu_welcome_user_notification
NEEDED TO LOAD MULTISITE found in file wp-includes/ms-load.php (since 3.0.0). get_current_site_name is_subdomain_install ms_not_installed ms_site_check wpmu_current_site wpautop wptexturize wp_filter_kses wp_filter_post_kses wp_filter_nohtml_kses wp_iso_descrambler wp_kses wp_kses_array_lc wp_kses_attr wp_kses_bad_protocol wp_kses_bad_protocol_once wp_kses_bad_protocol_once2 wp_kses_check_attr_val wp_kses_decode_entities wp_kses_hair wp_kses_hook wp_kses_html_error wp_kses_js_entities wp_kses_no_null wp_kses_normalize_entities wp_kses_normalize_entities2 wp_kses_split wp_kses_split2 wp_kses_stripslashes wp_kses_version wp_make_link_relative wp_rel_nofollow wp_richedit_pre wp_specialchars wp_trim_words zeroise
Pg 107 of 109
33
Notes
______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________ ______________________________________________________________
Pg 108 of 109 33
Back Page
THEME DESIGN Adding Navigation Menu support to a theme Developing a Colour Scheme Designing Headers CSS Horizontal Menus Dynamic Menu Highlighting Good Navigation Links Next and Previous Links Styling for Print Styling for Mobile Designing Your Post Meta Data Section Separating Categories in Post Meta Data Section Using Custom Fields with Post-Meta Customizing the Read More Customizing the Login Form Adding Administration Menus Formatting Date and Time Styling Lists with CSS Designing Headings Playing With Fonts Using Images Wrapping Text Around Images Fun Character Entities Smilies How to Use Gravatars in WordPress Adding Asides Protecting Your Email Address from Harvesters Theme Development Theme Review Theme Functions File Explained WORDPRESS AND CSS CSS - CSS within WordPress, and list of resources Know Your Sources - HTML, PHP, and CSS in general CSS Coding Standards - Best practices for coding CSS CSS Troubleshooting - Examining and debugging CSS CHEAT SHEETS http://creativeoverflow.net/4-advanced-wordpress-3-0-cheatsheets/ TUTORIALS http://wp.tutsplus.com/ http://codex.wordpress.org/Blog_Design_and_Layout www.siteground.com/tutorials/wordpress/ http://codex.wordpress.org/WordPress_Lessons http://themeshaper.com/2009/06/22/wordpress-themestemplates-tutorial/ First Steps With WordPress Using WordPress Themes Theme Development FAQ Themes, Layout and Design WordPress Lessons Lessons: Designing Your WordPress Site Lessons: Customizing Template Files WordPress Site Reviews DOCUMENATION http://codex.wordpress.org/Function_Reference http://www.dbswebsite.com/design/wordpress-reference/V3/ http://wpcandy.com/made/wordpress-reference-guide http://www.dailydocumentation.com/wordpress/ http://adambrown.info/p/wp_hooks
Pg 109 of 109 33