EDIT
From the comments from the OP
There’s a few concerns though and suggestions on improvement. First of all, not sure if i missed something, but the list are not links? Second is that with this list it outputs a letter even though it doesn’t have a post assigned to the letter…..
and
Posts that starts with an number won’t be listed, would it be possible to extend the range for this?
I have totally rewritten the entire code. Still, both blocks of codes in your question had major issues, so again, I’ve dropped both. As well as @birgire indicated, the code in my original answer had the drawback of the amount of db queries due the fact that I was including empty letters as well (thought this is what you wanted)
I have made the links clickable, as well as made provision to include numbers as the first character to sort by. What I did not go into detail in is styling.
So here are the revised code
<?php
$args=array(
'post_type' => 'portfolio',
'portfolio-category' => 'indie',
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page'=>-1,
'ignore_sticky_posts'=>1
);
$my_query = new WP_Query($args);
$q = array();
if( $my_query->have_posts() ) {
while ($my_query->have_posts()) {
$my_query->the_post();
$t="<a href="". get_permalink() .'" rel="bookmark" title="Permanent Link to '. get_the_title() .'">' . get_the_title() .'</a>';
$c = strtoupper(substr(get_the_title(),0,1));
$q[$c][] = $t;
}
}
wp_reset_postdata(); // Restore global post data stomped by the_post().
$count = 0;
foreach ($q as $key=>$values) {
$count++; ?>
<div class="column<?php echo $count; ?>" style="width:9%; margin-right:2%; float:left; margin-bottom:25px">
<?php echo $key;
foreach ($values as $value) { ?>
<div style="width:95%; padding-right:5%">
<p>
<?php echo $value; ?>
</p>
</div>
<?php } ?>
</div>
<?php if( 0 == $count%9 ){ ?>
<div class="clear" style="clear:left"></div>
<?php }
}
Here is the output from the code above
WHAT YOU NEED TO DO
-
Scrap everything from the original answer. I’m keeping the original answer for the sake of its completeness and that it might become useful to someone else in future.
-
Add your own styling and style according to your needs
-
Make any modification to suite your own personal needs
I have given you the backbone to accomplish your needs. I would expect that this would take to at least 99% in achieving your goal. Please let me know on your progress
ORIGINAL ANSWER
I’ve went a took a different route that what you took in your examples. Here is what I did and how it works:
STEP 1
@birgire did this post a while ago about extending the WP_Query
class which enables you to retrieve a post by first letter. Is is done with the introduction of a new parameter, name__like
. I’ve used this to create the custom query. Here is the new class
/**
* Class WPSE_Query
*
* Add a support for the name__like parameter
*
* @link https://wordpress.stackexchange.com/a/136758/26350
*
*/
class WPSE_Query extends WP_Query
{
public function __construct( $args = array() )
{
add_filter( 'posts_where', array( $this, 'posts_where' ), 10, 2 );
parent::__construct( $args );
}
public function posts_where( $where, $qry )
{
remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
$name__like = $qry->get( 'name__like' );
if( ! empty( $name__like ) )
{
$where .= " AND ";
$where .= $GLOBALS['wpdb']->posts;
$where .= ".post_name LIKE '";
$where .= esc_sql( like_escape( $name__like ) );
$where .= "%' ";
}
return $where;
}
}
This goes into your functions.php.
STEP 2
To dynamically retrieve a list of all letters of the alphabet, I’ve used the php function range()
and assigned a variable to it.
$range = range('A','Z');
STEP 3
I’ve then passed my variable through a foreach
loop to get all the individual letters, which is passed to my custom query
foreach ($range as $r){ }
STEP 4
Instead of using WP_Query
, I’ve now used the new class that was created in STEP 1 called WPSE_Query
. I also used the new parameter name__like
and passed each letter of the alphabet to it to retrieve my posts accordingly
$args = array(
'post_type' => 'portfolio',
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => -1,
'portfolio-category' => 'indie',
'ignore_sticky_posts' => 1,
'name__like' => $r
);
// The Query
$the_query = new WPSE_Query( $args );
The reason why I went through all this trouble is to give me more control over the HTML
STEP 5
I’ve introduced a counter to control when HTML elements are introduced and how they are advanced
STEP 6
To create and style the columns, I have used the following line. Note: I’ve used inline styles here just to showcase the output. You should add these styles to your stylesheet rather than keeping them as inline styles
<div class="column<?php echo $count; ?>" style="width:9%; margin-right:2%; float:left; margin-bottom:25px">
As you can see, I have used the counter here to advance my column class by one on each iteration
STEP 7
Finally, to stop any wacky output, you need to clear the float after every ninth post. With the use of the counter and the modulus division operator, a clear float is inserted after every ninth post
if( 0 == $count%9 ){ ?>
<div class="clear" style="clear:left"></div>
<?php }
ALL TOGETHER NOW!
This is the final code:
<?php
$count = 0;
$range = range('A','Z');
foreach ($range as $r){
$count++;
?>
<div class="column<?php echo $count; ?>" style="width:9%; margin-right:2%; float:left; margin-bottom:25px">
<?php
echo '<p>' .$r . '</p>';
// $args for the custom query
$args = array(
'post_type' => 'portfolio',
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => -1,
'portfolio-category' => 'indie',
'ignore_sticky_posts' => 1,
'name__like' => $r
);
// The Query
$the_query = new WPSE_Query( $args );
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
?>
<div style="width:95%; padding-right:5%">
<p>
<?php the_title(); ?>
</p>
</div>
<?php
}
}
wp_reset_postdata(); ?>
</div>
<?php
if( 0 == $count%9 ){ ?>
<div class="clear" style="clear:left"></div>
<?php }
}
?>
All you need to do is to tweak and add all relevant HTML mark-up
Here is the output from the code above
and here is the HTML structure