WordPress is awesome. Even more awesome is the fact that it can be customized to power any type of site you like! Here, we'll be learning how to create a featured and "latest posts" section - easily a 'must-have' for all good News/Magazine themes. We'll also go over using the 'Custom Fields' to their fullest potential.
Introduction
This tutorial covers process of creating the index page of a magazine/news theme for WordPress. The main features of this page will be:
- Featured Posts.
- Latest Posts.
- Using PHP Variables for easy customisation of the above for users of your theme not familiar with PHP/WordPress.
- Retrieving a post image from the ‘Custom Fields’ section of a post.
Step 1 - Preparation
From your WordPress installation directory, browse through ‘wp-content/themes’ and create a new folder. Name it how you wish (I’m using ‘WordPress Times’). Next, create 5 new files:
- index.php
- header.php
- footer.php
- style.css
This is the basic layout we’ll be going for:



So a 940px document, with two sections:
Content at 600px & Sidebar at 300px – leaving 40px margin between the two.
Step 2 - Header
Open your header.php file, and insert the following:
1 |
|
2 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3 |
<html xmlns="http://www.w3.org/1999/xhtml" <?php language_attributes(); ?>> |
4 |
<head>
|
5 |
<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" /> |
6 |
<meta name="description" content="<?php bloginfo('description'); ?>" /> |
7 |
<meta name="keywords" content="<?php bloginfo('name'); ?>" /> |
8 |
<meta name="author" content="<?php bloginfo('name'); ?>" /> |
9 |
<meta name="generator" content="WordPress <?php bloginfo('version'); ?>" /> |
10 |
<link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" type="text/css" media="screen, projection" /> |
11 |
<link rel="alternate" type="application/rss+xml" title="<?php bloginfo('name'); ?> RSS Feed" href="<?php bloginfo('rss2_url'); ?>" /> |
12 |
<link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" /> |
13 |
<title><?php bloginfo('name'); ?> <?php wp_title('-'); ?></title> |
14 |
<?php wp_head(); ?> |
15 |
</head>
|
16 |
<body>
|
17 |
<div class="container"> |
18 |
<h1 id="header"><?php bloginfo('name'); ?></h1> |
Running through this, we first define the DOCType as XHTML 1.0 Transitional. In the head section we then set all the meta tags, stylesheet and page titles to be retrieved from WordPress; and we include our 3 JavaScript files.
Finally, we open a ‘container’ division, and insert our blog’s name as a header title.
Step 3 - 'Breaking News' Posts
We will be including a user-defined number of posts from a ‘Breaking News’ category at the top of our page. Open index.php and type the following, don’t worry, I’ll explain it all below:
1 |
|
2 |
<?php get_header(); ?> |
3 |
<div id="content"> |
4 |
|
5 |
<?php global $more; |
6 |
$more = 0; ?> |
7 |
|
8 |
<?php
|
9 |
|
10 |
/* ID of your 'Breaking News' Category */
|
11 |
$breaking_cat = "83"; |
12 |
|
13 |
/* How many posts from above category to display? Default = 3 */
|
14 |
$breaking_num = "3"; |
15 |
|
16 |
/* Number of recent posts to display under the Breaking News */
|
17 |
$latest_num = "4"; |
18 |
|
19 |
/* IDs of any cats you dont want to include in Recent posts.
|
20 |
Start each ID with a 'minus' symbol Seperate by a comma.
|
21 |
EG: $latest_ignore = "7,-6,-8,-1";
|
22 |
Posts from the 'Breaking' category are automatically excluded. */
|
23 |
$latest_ignore = "-1"; |
24 |
?>
|
25 |
|
26 |
<!-- Show x Posts from Breaking News -->
|
27 |
<?php query_posts('showposts='.$breaking_num.'&cat='.$breaking_cat.''); |
28 |
while (have_posts()) : the_post(); |
29 |
?>
|
30 |
|
31 |
<div class="breaking"> |
32 |
|
33 |
<img src="<?php echo get_post_meta($post->ID, 'thumbnail',true) ?>" alt="Post Image" class="postimg" /> |
34 |
<h2><a href="<?php the_permalink() ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></h2> |
35 |
<p class="datetime"><?php the_time('l, F j, Y G:i'); ?></p> |
36 |
<?php the_content('Continue...'); ?> |
37 |
<div class="postmeta"> |
38 |
<p><?php the_category(', '); ?> - <a href="<?php the_permalink() ?>#commenting" title="View Comments"> |
39 |
<span class="comm"><?php comments_number('0 Comments','1 Comment','% Comments'); ?></span></a></p> |
40 |
</div><!--/postmeta--> |
41 |
|
42 |
</div><!--/breaking--> |
43 |
|
44 |
<?php endwhile; ?> |
3.1 - Opening
1 |
|
2 |
<?php get_header(); ?> |
3 |
<div id="content"> |
The first line is a simple WordPress PHP function to include our header.php file first. Below that, we open our ‘Content’ div to wrap all the posts together. I have included a HTML comment at the closing of every div tag stating which div it is closing. I highly recommend that you start doing this in your own projects if you don’t already, as it helps keep your code as organized as possible.
3.2 - The $more tag
1 |
|
2 |
<?php global $more; |
3 |
$more = 0; ?> |
This code allows us to only include part of each post up to where the author has included the <--more--> tag – this stops all the text in long posts from displaying on the homepage.
3.3 - Category IDs
1 |
|
2 |
$breaking_cat = "83"; |
3 |
$breaking_num = "3"; |
4 |
|
5 |
$latest_num = "4"; |
6 |
$latest_ignore = "-1"; |
In order to make customizing the theme easier, we include any options here. Each line is commented to further. We do this so that if someone else uses your theme - instead of having to crawl through all your code to find where to put their category IDs - they are all easily accessible at the top of the file. Throughout this tutorial, we will be using these variables in the WordPress loop.
3.4 - Do we have Posts?
1 |
|
2 |
<?php query_posts('showposts='.$breaking_num.'&cat='.$breaking_cat.''); |
3 |
while (have_posts()) : the_post(); |
4 |
?>
|
This is a variation of the WordPress loop that outputs our posts from the database. As you can see, we are using the first two of our variables from the section above. The variables substitute themselves with the string associated with them. For example, using the default code, the line would automatically become:
1 |
|
2 |
query_posts('showposts=3&cat=83') |
The second line then says, if we have the posts then insert them into the page in the format outlined below.
3.5 - Post Content
1 |
|
2 |
<img src="<?php echo get_post_meta($post->ID, 'thumbnail',true) ?>" alt="Post Image" class="postimg" /> |
3 |
|
4 |
<h2><a href="<?php the_permalink() ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></h2> |
5 |
|
6 |
<p class="datetime"><?php the_time('l, F j, Y G:i'); ?></p> |
7 |
|
8 |
<?php the_content('Continue...'); ?> |
This isn't as scary as it looks, trust me.
-
Image - On our homepage preview, you will notice that each post has its own image. This is included using WordPress’ “Custom Fields” section when writing a post. Simply set the ‘key’ to thumbnail then insert the link to the image:
The code essentially says “Take the data from the post’s custom field named ‘thumbnail’ and stick it into an img tag.”
- Title - This inserts our post title as a link in between h2 tags. the_permalink() gets the post’s link, and the_title() retrieves the title. Pretty simple, huh?
- Date & Time - Here, we get the time the post was made, in the format of: l, F j, Y G:i – or in English: Day, Date, Year Time (eg. Saturday, August 2, 2008 14:27).
- Content - Retrieves the post’s content up to the (thanks to the code we included earlier). ‘Continue...’ is the text displayed at the end of the post. Customise this however you like.
3.6 - Post Meta
1 |
|
2 |
<div class="postmeta"> |
3 |
|
4 |
<p><?php the_category(', '); ?> - <a href="<?php the_permalink() ?>#commenting" title="View Comments"> |
5 |
|
6 |
<span class="comm"><?php comments_number('0 Comments','1 Comment','% Comments'); ?></span></a></p> |
7 |
|
8 |
</div>
|
This retrieves the category(s) the post is from. If there’s more than one, they will be separated by commas. A link to the comments section, and the number of comments in the article is then retrieved.
1 |
|
2 |
</div> <!-- /breaking --> |
3 |
<?php endwhile; ?> |
This simply closes the "div.breaking" that our post was in; and then closes the loop once it is done.
Step 4 - Latest Posts
Below our three ‘Breaking News’ posts, we will include a user-specified number of latest posts, while ignoring any posts from the ‘Breaking’ category, and any of the other user-specified categories to ignore. We'll add the following to the bottom of our current code:
1 |
|
2 |
<!-- Show x Latest Posts -->
|
3 |
<?php query_posts('showposts='.$latest_num.'&cat=-'.$breaking_cat.','.$latest_ignore.''); ?> |
4 |
<?php while (have_posts()) : the_post(); ?> |
5 |
|
6 |
|
7 |
<div class="recent"> |
8 |
|
9 |
<img src="<?php echo get_post_meta($post->ID, 'thumbnail',true) ?>" alt="Post Image" class="postimg-s" /> |
10 |
<h3><a href="<?php the_permalink() ?>" title="<?php the_title(); ?>"><?php the_title(); ?></a></h3> |
11 |
<p class="datetime"><?php the_time('l, F j, Y G:i'); ?></p> |
12 |
<div class="postmeta"> |
13 |
<p><?php the_category(', '); ?> - <a href="<?php the_permalink() ?>#commenting" title="View Comments"> |
14 |
<span class="comm"><?php comments_number('0 Comments','1 Comment','% Comments'); ?></span></a></p> |
15 |
</div>
|
16 |
|
17 |
</div>
|
18 |
|
19 |
|
20 |
<?php endwhile; ?> |
4.1 - The Loop
- showposts='.$latest_num.' - Tells the loop to only display the number of recent posts the user has specified in the ‘$latest_num’ variable.
- cat=-'.$breaking_cat.','.$latest_ignore.' - This instructs the loop to ignore (note the ‘minus’ symbol we require the user to use in the variables) posts which are in the ‘Breaking’ category so as not to duplicate any posts; and also to ignore posts from any of the categories which the user specifies in the ‘$latest_ignore’ variable.
The rest of it is self-explanatory and the same as the Breaking News feature. A few differences are the lack of the ‘content’ section from each post, and also the post image is given the class of ‘postimg-s’ instead. This will allow us to only require one thumbnail image – which we will then size down in our CSS from 200x200 to 50x50.
4.2 - Closing the page
In order to end the current page, we need to close the div#content and include our footer:
1 |
|
2 |
</div><!--/content--> |
3 |
<?php get_footer(); ?> |
4.3 - Footer.php
In this file, simply close the #container, body and html tags:
1 |
|
2 |
</div><!--/container--> |
3 |
</body>
|
4 |
</html>
|
Step 5 - CSS Styling
Right now, if you’ve created some posts, your design should look something like this:



Pretty ugly, eh? Well not for much longer.
5.1 - Necessities
Open up your style.css file and paste in the following code:
1 |
|
2 |
/*------------------------------------------------------------------------
|
3 |
Theme Name: WordPress Times
|
4 |
Theme URI: http://www.vivawp.com/
|
5 |
Description: A tutorial for NETTUTS.com by Dan Harper
|
6 |
Version: 1.00
|
7 |
Author: Dan Harper
|
8 |
Author URI: http://danharper.me
|
9 |
------------------------------------------------------------------------*/
|
This is required at the top of this file, as it gives the Theme Manager in WordPress some information about your theme. Fill in the sections in it as you like.
5.2 - Styling
Below is all the CSS code used for styling the document. It is documented below.
1 |
|
2 |
* {margin:0;padding:0;} |
3 |
|
4 |
body { |
5 |
background-color: #faf9f5; |
6 |
color: #3d3d3d; |
7 |
font-size:75%; |
8 |
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; |
9 |
}
|
10 |
|
11 |
#container {
|
12 |
width: 940px; |
13 |
margin: 15px auto; |
14 |
}
|
15 |
|
16 |
h1, h2, h3, h4, h5, h6 { |
17 |
font-family: Georgia, "Times New Roman", Times, serif; |
18 |
}
|
19 |
|
20 |
/* BLUEPRINT CSS TYPOGRAPHY */
|
21 |
h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} |
22 |
h1 {font-size:3em;line-height:1;margin-bottom:0.5em;} |
23 |
h2 {font-size:2em;margin-bottom:0.75em;} |
24 |
h3 {font-size:1.5em;line-height:1;margin-bottom:1em;} |
25 |
h4 {font-size:1.2em;line-height:1.25;margin-bottom:1.25em;height:1.25em;} |
26 |
h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} |
27 |
h6 {font-size:1em;font-weight:bold;} |
28 |
h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} |
29 |
p {margin:0 0 1.5em;} |
30 |
li ul, li ol {margin:0 1.5em;} |
31 |
ul, ol {margin:0 1.5em 1.5em 1.5em;} |
32 |
/* /BLUEPRINT CSS TYPOGRAPHY */
|
33 |
|
34 |
h1#header { |
35 |
margin-bottom: 20px; |
36 |
}
|
37 |
|
38 |
#content {
|
39 |
width: 600px; |
40 |
float: left; |
41 |
}
|
42 |
|
43 |
.breaking, .recent { |
44 |
padding: 10px; |
45 |
border: 1px solid #3d3d3d; |
46 |
margin-bottom: 15px; |
47 |
}
|
48 |
|
49 |
.postimg { |
50 |
float: right; |
51 |
width: 200px; |
52 |
height: 200px; |
53 |
padding-bottom: 10px; |
54 |
}
|
55 |
|
56 |
.postimg-s { |
57 |
float: right; |
58 |
width: 50px; |
59 |
height: 50px; |
60 |
padding-bottom: 10px; |
61 |
}
|
62 |
|
63 |
.breaking h2 { |
64 |
font-size: 2.5em; |
65 |
line-height: 1em; |
66 |
margin-bottom: 0px; |
67 |
}
|
68 |
|
69 |
.breaking h2 a, .recent h3 a { |
70 |
text-decoration: none; |
71 |
color: #3d3d3d; |
72 |
}
|
73 |
|
74 |
.breaking h2 a:hover, .recent h3 a:hover { |
75 |
text-decoration: underline; |
76 |
}
|
77 |
|
78 |
p.datetime { |
79 |
font-style: italic; |
80 |
font-size: 0.9em; |
81 |
}
|
82 |
|
83 |
/* POST META */
|
84 |
.postmeta { |
85 |
margin: -10px; |
86 |
padding: 4px; |
87 |
background-color: #dedbd1; |
88 |
clear: both; |
89 |
}
|
90 |
|
91 |
.postmeta p { |
92 |
margin: 0; |
93 |
padding-left: 6px; |
94 |
text-transform: uppercase; |
95 |
font-weight: bold; |
96 |
}
|
97 |
|
98 |
.postmeta span.comm { |
99 |
font-weight: normal; |
100 |
}
|
101 |
|
102 |
.postmeta a:link, .postmeta a:visited { |
103 |
color: #3d3d3d; |
104 |
text-decoration: none; |
105 |
}
|
106 |
|
107 |
.postmeta a:hover, .postmeta a:active { |
108 |
text-decoration: underline; |
109 |
}
|
110 |
|
111 |
#sidebar {
|
112 |
width: 300px; |
113 |
margin-left: 620px; |
114 |
}
|
5.3 - Examining the CSS
- * - Removes un-wanted margins and paddings from all elements that browsers insert themselves.
- body - Basic page styling of colours and fonts.
- #container - Sets the page width to 940px. 15px margin at the top & bottom, and centres it in the window.
- h1, h2, h3, h4, h5, h6 - Heading fonts to Georgia, Times New Roman, Times or any serif font.
- Between Blueprint comments tags - Basic typography styling from the Blueprint CSS Framework. Saves a lot of hassle with getting text to look nice.
- h1#header - Adds a bit of separation from the Blog name, and the rest of the document.
- #content - All our content is wrapped in 600px on the left. The remaining space can be used as a sidebar.
- .breaking, .recent - Includes Breaking and Recent posts in a box with 10px padding. 15px gap between each one.
- .postimg - Formats the Post's Image for Breaking articles. Image size limited to 200px and floated right.
- .postimg-s - Same as above, but for Latest articles and the image is resized to 50px.
- .breaking h2 - Makes title of Breaking articles smaller, with no bottom margin.
- .breaking h2 a, .recent h3 a - Basic styling for titles of articles, hiding the default link style.
- .breaking h2 a:hover, .recent h3 a:hover - Adds an underline to title link when hovered over to show the user it is in-fact a link.
- p.datetime - Date & Time string for articles made slightly smaller, and in italics.
- .postmeta - Creates box to include the Post Meta details (categories & comments). margin -10px ensures it fills the whole of the posts box.
- .postmeta p - Text in postmeta div is made uppercase and bold.
- .postmeta span.comm - Removes the bold styling for the "x Comments" text.
- .postmeta a - Link styling to remove default link colour.
- .postmeta a:hover - Adds underline to links on hover.
- #sidebar - Creates an area for a sidebar down the right side of the page.
The page will now look like this. Much cleaner!



Conclusion
Congrats. You have successfully created the basics for the front page of a news theme for WordPress, complete with a Featured post area – a ‘must-have’ when it comes to News themes. You can also stay ahead of the competition with your easy customisation options using the PHP variables.
Look out for the launch of vivaWP – a new family of Premium WordPress themes coming mid-August. Our first theme, CocoaNews, shares some of the basic code shown throughout this tutorial.