Template to List Posts By First Letter of Title, 1 Letter Per Page
This template is a variation of the one that shows posts or pages by first letter of title with a selected number of posts per page.
The template is written for the Twenty Ten theme. You will probably need to modify it to tweak the appearance or work with a different theme. The embedded CSS should really be moved to your stylesheet.
<?php
/*
Template Name: A-Z Pages by Letter
A WordPress template to list page titles by first letter.
You should modify the CSS to suit your theme and place it in its proper file.
Be sure to set the $posts_per_row and $posts_per_page variables.
*/
// This function should go in functions.php
function mam_posts_where ($where) {
global $mam_global_where;
if ($mam_global_where) $where .= " $mam_global_where";
return $where;
}
add_filter('posts_where','mam_posts_where');
$posts_per_row = 3;
$posts_per_page = -1;
$pageURL = 'http';
$post_type = 'post';
if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";}
$pageURL .= "://";
if ($_SERVER["SERVER_PORT"] != "80") {
$pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
} else {
$pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
}
$letters = $wpdb->get_col(
"SELECT DISTINCT LEFT(post_title,1) AS first_letter FROM $wpdb->posts
WHERE post_type = '$post_type' AND post_status = 'publish'
ORDER BY first_letter ASC"
);
$first_letter = ($_GET['first_letter']) ? $_GET['first_letter'] : $letters[0];
?>
<?php get_header(); ?>
<style type="text/css">
.letter-group { width: 100%; }
.letter-cell { width: 5%; height: 2em; text-align: center; padding-top: 8px; margin-bottom: 8px; background: #e0e0e0; float: left; }
.row-cells { width: 70%; float: right; margin-right: 180px; }
.title-cell { width: 30%; float: left; overflow: hidden; margin-bottom: 8px; }
.clear { clear: both; }
</style>
<div id="main-background">
<div id="main-column">
<h1><?php the_title(); ?></h1>
<div class="margin-top"></div>
<div id="a-z">
<?php
$mam_global_where = " AND LEFT(post_title,1) = '$first_letter' ";
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array (
'posts_per_page' => $posts_per_page,
'post_type' => $post_type,
'orderby' => 'title',
'order' => 'ASC',
'paged' => $paged,
'caller_get_posts' => 1
);
query_posts($args);
$mam_global_where = ''; // Turn off filter
if ( have_posts() ) {
$in_this_row = 0;
while ( have_posts() ) {
the_post();
$first_letter = strtoupper(substr(apply_filters('the_title',$post->post_title),0,1));
if ($first_letter != $curr_letter) {
if (++$post_count > 1) {
end_prev_letter();
}
start_new_letter($first_letter);
$curr_letter = $first_letter;
}
if (++$in_this_row > $posts_per_row) {
end_prev_row();
start_new_row();
++$in_this_row; // Account for this first post
} ?>
<div class="title-cell"><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></div>
<?php }
end_prev_letter();
?>
<div class="navigation">
<?php
foreach ($letters as $letter) {
$url = add_query_arg('first_letter',$letter,$pageURL);
echo "<a href='$url' title='Starting letter $letter' >[ $letter ] </a>";
}
?>
</div>
<?php } else {
echo "<h2>Sorry, no posts were found!</h2>";
}
?>
</div><!-- End id='a-z' -->
</div><!-- End class='margin-top -->
</div><!-- End id='rightcolumn' -->
<?php get_sidebar(); ?>
<?php get_footer(); ?>
<?php
function end_prev_letter() {
end_prev_row();
echo "</div><!-- End of letter-group -->\n";
echo "<div class='clear'></div>\n";
}
function start_new_letter($letter) {
echo "<div class='letter-group'>\n";
echo "\t<div class='letter-cell'>$letter</div>\n";
start_new_row($letter);
}
function end_prev_row() {
echo "\t</div><!-- End row-cells -->\n";
}
function start_new_row() {
global $in_this_row;
$in_this_row = 0;
echo "\t<div class='row-cells'>\n";
}
?>
I don’t use the Twenty Ten theme I have my own custom theme. The code doesn’t seem to work. I end up getting a blank page. What could be wrong?
Since I do not know the structure of your custom theme, or how it might compare to Twenty Ten, there is no possible way that I can even guess what might be wrong.
This is my function http://pastebin.com/4NXxTR3T
and this is my page template http://pastebin.com/zDuGXKMn
I get a blank page if I uploaded the function file
You have put too much code into functions.php. Only lines 11 – 17 go in functions.php. The rest stay in your template.
Just another question.. Everything above is working properly, but I want a [ALL] text alongside the [A] [B] that would display all the posts of that category.
I can’t think of an easy way to do that right now.
Creating an ALL choice for each letter will make the menu extremely long.
Creating a single ALL might involve creating a form for the menu with a checkbox for the ALL choice – fairly major modification to the code.
If I think of an easier way, I will let you know.
This works like a charm! But i need to tweak it a little bit, I hope you can help me!
I want the posts of specific categories to be displayed. Suppose, I have two categories “Cats” and “Dogs”. When I click on “Cats” I should get all the posts, 1 letter per page related to that category and its sub-categories! I have made a change. I have put ‘cat’ => 13, in the $args array. I am getting the posts related to category 13 but the problem is the navigation of the letters. In category 13 I have posts starting with letters “a” and “b”, but the code is displaying letters “c” and “d” also in the navigation part
Could this be done? If yes, what changes need to be made.
You only need to change the query that selects the letters. Try changing this:
to this:
With some small changes, I got what I wanted! Thank you very much, your help is much appreciated!
Hi Guys, nice code.
I am wondering if it can work with authors’ list. is that possible and how?
I tried to play with the code by no hope
Please help me, I need this urgently
Thank You guys
Seteve
Hello Steve,
Do you have code now that is working to give an author’s list with the information you want? If so, please post it in a pastebin, and use the Contact Me page to send me a link to it.
Well, it was a temporary draft page and probably the drafts are available in wordpress only to admins or users that are allowed to view unpublished content. I do not want to loose your precious time so if you can manage to fix the code and would not mind to share it, It would be wonderful. If not, please do not hesitate as I am sure you have lots of daily tasks and nicer things to do
Thank you anyway for the help or at least the willing to help
I would like to continue this by email. Please check the email you used to enter the comments.
btw, I do not know whether I am allowed to post links, but probably it would be easier if you can see the results?
Here is the link
Hi Mike,
I see what is causing the problem, but I do not yet have a fix. I will post again when I find an answer.
Unfortunately, your link gives a 404 error, but I believe I do not need it.
Well it turned out that for 3 years of post writing and using cyrillic in post titles we have managed to get an array of all this letters and symbols:
” & 0 1 2 3 4 5 7 8 9 B J K T U Y А Б В Г Д Е З И К Л М Н О П Р С Т У Ф Х Ц Ч Ш Я
So what I would love to have is to group all the numbers and other symbols different from letters in a group [0-9-&] [А] [Б] etc. until the end of the alphabet. So how to group the posts with all the digits and symbols in one link?
I don’t know if all of the code is multi-byte character compatible and I have not tested this, but it is worth a try. Change this:
$first_letter = strtoupper(substr(apply_filters('the_title',$post->post_title),0,1)); if ($first_letter != $curr_letter) {to this:
$first_letter = strtoupper(substr(apply_filters('the_title',$post->post_title),0,1)); if (strpos('&0123456789',$first_letter) !== false) $first_letter = '&-0-9'; if ($first_letter != $curr_letter) {Hi Mac,
thank you very much for your fast reply. I really really appreciate your willing to help, however something is missing in the code you have kindly provided as it is still showing all the digits and letters even thoug I tested it with English alphabet and digits mix on fresh wordpress installation. Any ideas?
Hi Mac,
I have tested your piece of code and it worked like a charm. I only need to polish the CSS style now.
I have a question though how can I show before the letters another link that can search for any posts starting with a digit (for example: [ 0-9 ] ). Otherwise if I have 10 posts starting with the digits from 0 to 9 and 30 posts for all the letters the list would become too long and most likely would overflow one line?
Thanks in advance for your help and support!
Hi Mac,
Thk!!!
Hi,
Fantistic is work perfect
I have a question, it’s possible to list all the letters??, not only the existing first letter.
Thks!
Sorry for my english :/
It would not be possible without major changes to the template. Besides, the letters without posts would link to empty pages with ‘No Posts Found’ messages.
Sorry for the bump, but the code is missing;
I mean is for page title:
Archive A - Domain.Com , Archive A - Domain.Comand so on.Thanks
This has not been exhaustively tested, but I think it will work.
Add code to get the domain under the line that sets $first_letter:
$first_letter = ($_GET['first_letter']) ? $_GET['first_letter'] : $letters[0]; $siteurl = get_option('siteurl'); //or home $domain_terms = explode('/', str_replace('www.', '', str_replace('http://', '', $siteurl))); $domain = $domain_terms[0];And change this:
to this:
<h1><?php echo "Archive $first_letter - $domain"; ?></h1>Hello Mac,
I really like this template. but I would like to customize the url of the page become more search engine friendly like:
domain.com/archives/a
domain.com/archives/b
also on page Archive A – Domain.Com , Archive A – Domain.Com and so on.
Please help me,
Thank You
I don’t know how to change the URL of the page the way you want.
Could you help me regarding the Arabic letters.see my previous replay.
Try changing this:
function start_new_letter($letter) { echo "<div class='letter-group'>\n"; echo "\t<div class='letter-cell'>$letter</div>\n"; start_new_row($letter); }to this:
function start_new_letter($letter) { echo "<div class='letter-group'>\n"; echo "\t<div class='letter-cell'>" . mb_convert_encoding($letter,'UTF-8', mb_detect_encoding($letter) ) . "</div>\n"; start_new_row($letter); }Good day,
I have problem with letter-cell.when I tray to use Arabic letters for example it shows others samples could you help? while I have no problem letter row (where all letters listed as links)
Good day,
I would like to customize every letter ( [A] [B [C]….etc] which means I need to give a .css properties to every letter , how can I do that?
Try changing this line (line 98):
echo "<a href='$url' title='Starting letter $letter' >[ $letter ] </a>";to this:
echo "<a href='$url' title='Starting letter $letter' ><span class='letter-$letter'>[ $letter ]</span> </a>";It is not working
Oh
I found the solution. Actually your code is working but the class name ‘letter-$letter’ is not acceptable. I changed it to ‘Myletters’ and it works
Thank you Mac
Thank you very much for the excellent support
Did you set $post_type = ‘post’ at the top?
This has caused a lot of confusion, so I will change it now in the source.
I am using itheme2. when I use this code in my new page template it show the pages not the posts!!
Yes. I’ve done that. It has to do with moving to another page so I’m looking for something to do
Thanks all the same.
I did tried the unedited code but got the same result. Still if you’re happy with the solution then I’ll keep it. Another issue, but which has nothing to do with the script itself, is that I’ve been trying to attach a :focus to the $letter in order to style it when on the page related to a letter. However, nothing works for me. Any ideas?
By the way, are you for hire? Sometimes I wouldn’t mind paying for help with bits and pieces.
Thanks
Did you notice that there is sample CSS in the code? You should remove that and place it in your style.css. Then you can modify it to suit.
Sorry, I don’t do work for hire. This is only a hobby for me, and I don’t want it to be anything more.
Hello Mac,
It worked perfectly! Now i have it displaying by meta_value also. The only bit I couldn’t make work was
$first_letter = strtoupper(substr($post->meta_value,0,1)); in order to display the first letter.
I managed to display the first letter with
$business = get_post_meta( $post->ID, ‘business’, true );
$first_letter = strtoupper(substr($business,0,1));
Do you have a neater solution?
Thanks
Poli
Strange that the original code did not work, but your version seems good.
Now it does. Thanks. I will send you a link when the site is live so you can see how I’m using your template.
Many thanks
Poli
That’s fantastic! And thank you for your quick reply – although Pastebin doesn’t seem to recognize the paste’s ID so I couldn’t look at the code. Why that may be?
Poli
During testing, I discovered a bug and had to replace the pastebin. I have updated the comment now with the correct link.
Hello Mac,
I really like this template and it works great. The display of one letter per page is a big plus. I have been trying to make it work for displaying by custom field rather than by title but without success. How will be possible to achieve this? It was easy enough to select the letters by meta_value but I’m stuck on the filter. I’d really appreciate some help.
Thanks
Poli
The template required several changes to have it use the Custom Fields. The code is in a pastebin here:
http://pastebin.com/y8KBGNPk
Been looking for this functionality for a while.
One question though; is there anyway I can move the position of the navigation list above both the current letter and post list?
I have not tested it, but I think you can put this just after line 74 ($in_this_row = 0;):
?> <div class="navigation"> <?php foreach ($letters as $letter) { $url = add_query_arg('first_letter',$letter,$pageURL); echo "<a href='$url' title='Starting letter $letter' >[ $letter ] </a>"; } ?> </div> <?phpI got it working (maybe it is not correct php but it works) :
echo "";echo " $letter ";
echo "";
and css for this is:
.letter { display:inline; text-align: center; padding: 2px 5px; border-top: 1px solid #48465B; border-left: 1px solid #48465B; background: #18181C; margin: 0 5px;}working example here:
http://www.4ella.com/clubs/regione-e-lettera/?first_letter=P
I start to love this site , thank you for very quick and as always in previous tips very good working snippet.
Mac one more question : If I want to customize every letter , instead of [A] I would like to give a .css properties to every letter , how can I call the class?
let’s say I will want to style it :
.letter { text-align: center; padding: 2px 5px; border-top: 1px solid #48465B; border-left: 1px solid #48465B;background: #18181C; margin-right: 10px;}