How to list posts and wrap them alphabetically? - php

I have a list of posts on my website, what I'm trying to do is to wrap them alphabetically from A-Z by title to get a glossary like this:
A.
Apple
B.
Banana
C.
Carotts
D.
E.
F.
G.
Grenada
and so on untill letter z.
I want the letter to be displayed even if there's no post.
and i want to wrap results inside this structure :
<div class="group_letter">
<div class="letter">A</div>
<div class="post">Apple</div>
</div>
<div class="group_letter">
<div class="letter">B</div>
<div class="post">Banana</div>
</div>
here is what I've got so far :
<?php
$letter=' ';
query_posts( array ( 'post_type' => 'auteurs', 'orderby' => 'title', 'order' => 'ASC' ) );
if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php
$title=get_the_title();
$initial=strtoupper(substr($title,0,1));
if($initial!=$letter) {
echo "<div>$initial</div>";
$letter=$initial;
}
echo "<div class='post'>" . $title. "</div>";
?>
<?php endwhile; endif; wp_reset_query(); ?>
here is the result :
<div class='letter'>A</div>
<div class='post'>Apple</div>
<div class='letter'>B</div>
<div class='post'>Banana</div>
<div class='letter'>C</div>
<div class='post'>carotts</div>
<div class='letter'>G</div>
<div class='post'>Grenanda</div>
I have 2 problems :
Empty letters are not displayed.
I can't find a way to wrap my groups inside group_letter div.

I would solve this with a filter on WP_Query. One that detects an extra query variable.
Add this into your functions.php
add_filter( 'posts_where', 'title_filter', 10, 2 );
function title_filter( $where, &$wp_query )
{
global $wpdb;
if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
$where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( $wpdb->esc_like( $search_term ) ) . '%\'';
}
return $where;
}
Once you have filter in place you can use wp_query and array range of alphabet
foreach (range('A', 'Z') as $char) {
echo '<div class="group_letter">';
echo '<div class="letter">'.$char.'</div>';
$args = array(
'post_type' => 'auteurs',
'posts_per_page' => -1,
'search_prod_title' => $char,
'post_status' => 'publish',
'orderby' => 'title',
'order' => 'ASC'
);
$the_query = new WP_Query($args);
if ( $the_query->have_posts() ) :
while ( $the_query->have_posts() ) : $the_query->the_post();
$title=get_the_title();
$initial=strtoupper(substr($title,0,1));
if($initial==$char) {
echo "<div class='post'>" . $title. "</div>";
}
endwhile;
wp_reset_postdata();
endif;
echo '</div>';
}
remove_filter( 'posts_where', 'title_filter', 10, 2 );
I have not tested this code, I hope it should work.
You can get more information about Wp_query https://codex.wordpress.org/Class_Reference/WP_Query

Sorry, postin TV from phone, so may be not displaying properly
Firstly, you have to create an array of all alphabets.
$alph = array('A', 'B', 'C',.... 'Z');
<
?php
$title=get_the_title();
foreach($alph as $key) {
// add while loop here
initial=strtoupper(substr($title,0,1));
if($initial!=$key) {
echo '<div class="group_letter">';
echo "<div>$key</div>";
}else{
echo "<div class='post'>" . $title. "</div>";
}
echo "</div>";
// end while loop here
}
?>

Related

Wordpress loop: custom number of posts and sort by date

I have tried to find a solution to something I need on the website (example here: https://www.baiweb.nl/). I have been looking for a way to show a custom number of posts per category AND sort them by date. I have managed to get a single post per category, but I can't seem to fix the rest. It sorts the posts itself by date now, but not all of them.
So, my questions are:
Is it possible to sort this loop, with all different categories, by date?
Is it possible to control the number of posts shown per category? This one is extra for me, not essential, but it would be nice.
Hope someone can help! Thanks a lot in advance for your time!
Here is my code used in the loop now:
<?php
$categories = get_categories();
$cats = array();
foreach($categories as $category) {
$cats[] = $category->name . ", ";
}
$exclude_posts = array();
foreach( $cats as $cat ) {
// build query argument
$query_args = array(
'category_name' => $cat,
'showposts' => 1,
'post_type' => 'post',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'DESC'
);
// exclude post that already have been fetched
// this would be useful if multiple category is assigned for same post
if( !empty($exclude_posts) )
$query_args['post__not_in'] = $exclude_posts;
// do query
$query = new WP_Query( $query_args );
// check if query have any post
if ( $query->have_posts() ) {
// start loop
while ( $query->have_posts() ) {
// set post global
$query->the_post();
// add current post id to exclusion array
$exclude_posts[] = get_the_ID();
?>
<article id="post-<?php the_ID(); ?>" <?php post_class('loop');?>>
<div class="corner"><span><?php foreach((get_the_category()) as $category){ echo $category->name.'<br> '; } ?></span></div>
<!-- thumbnail -->
<a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>" class="image">
<?php
$thumb_id = get_post_thumbnail_id();
$thumb_url = wp_get_attachment_image_src($thumb_id,'medium', true);
if ( in_category('2') || in_category('32') ) {
echo '<div class="newstitle">' . the_title() . '</div>';
}
else {
if ( has_post_thumbnail()) {
echo "<div class='ctr-image test2' style='background-image: url(" . $thumb_url[0] . ")'></div>";
}
else {
echo '<div class="newstitle">' . the_title() . '</div>';
}
}
?>
</a>
<div class="content">
<span class="date"><?php the_time('j/m/Y'); ?></span>
<h3>
<a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>">
<?php if ( in_category('2') || in_category('32') ) {}
else { echo the_title();} ?>
</a>
</h3>
<div class="text">
<?php html5wp_excerpt('html5wp_index'); // Build your custom callback length in functions.php ?>
</div>
</div>
</article>
<?php
// do something
}
} else {
// no posts found
}
// Restore original Post Data
wp_reset_postdata();
} ?>
You were close. Your categories foreach loop has to englobe everything. Then we do a simple loop but we specify what arguments to use depending on each categories.
Here is our final result.
<?php
$categories = get_categories(); // ... get all our categories
foreach( $categories as $category ) { // ... start foreach categories
if ( $category->name == 'Mercury' ) { // ... if our category name is 'Mercury'
$posts_per_page = 1; // ... 1 post per page if our category is named 'Mercury'
} else { // ... else, for all other categories
$posts_per_page = 3; // ... 3 posts per page
};
$args = array( // ... all our arguments
'posts_per_page' => $posts_per_page, // ... 1 or 3 posts per page depending on our categories
'post_type' => 'post',
'category_name' => $category->name,
'post_status' => 'publish',
'orderby' => 'date', // ... order by date
'order' => 'ASC', // ... most recent first
);
$query = new WP_Query( $args ); // .. start a new loop
if( $query->have_posts() ):
echo '<section>';
echo '<h1>' . $category->name . '</h1>'; // ... only display our section IF a post exist in the category
while( $query->have_posts() ): $query->the_post();
echo '<article>'; // ... our post template
the_title( '<h4>', '</h4>' );
echo '</article>';
endwhile;
echo '</section>';
endif;
wp_reset_postdata(); // ... After looping through a separate query, this function restores the $post global to the current post in the main query.
}; // ... end foreach categories
?>
Thank you so much for your quick and comprehensive answer! The part of the number of categories is working very well, however, the outcome is slightly different than I want. It may be that my question was not clear, apologies for that.
What you have already made beautiful is all the categories with posts that belong to it. What I want to achieve is that all messages are mixed up, sorted by date and, what was already done here, I can indicate how many posts are in per category. Is that even possible?
Some screenshotsof the outcome of your code:
This is what I am trying, except now I need to sort this by date:
This is the code slightly adjusted:
<?php
$categories = get_categories(); // ... get all our categories
foreach( $categories as $category ) { // ... start foreach categories
if ( $category->name == 'Mercury' ) { // ... if our category name is 'Mercury'
$posts_per_page = 1; // ... 1 post per page if our category is named 'Mercury'
} else { // ... else, for all other categories
$posts_per_page = 2; // ... 3 posts per page
};
$args = array( // ... all our arguments
'posts_per_page' => $posts_per_page, // ... 1 or 3 posts per page depending on our categories
'post_type' => 'post',
'category_name' => $category->name,
'post_status' => 'publish',
'orderby' => 'date', // ... order by date
'order' => 'ASC', // ... most recent first
);
$query = new WP_Query( $args ); // .. start a new loop
if( $query->have_posts() ):
// echo '<section>';
// echo '<h1>' . $category->name . '</h1>'; // ... only display our section IF a post exist in the category
while( $query->have_posts() ): $query->the_post();
echo '<article>'; // ... our post template
echo '<h1>' . $category->name . '</h1>';
the_time('j/m/Y');
the_title( '<h4>', '</h4>' );
echo '</article>';
endwhile;
// echo '</section>';
endif;
wp_reset_postdata(); // ... After looping through a separate query, this function restores the $post global to the current post in the main query.
}; // ... end foreach categories ?>
Hope this is clear, thanks again!

List each custom post type separately in a wp_query without repeating the loop

I'm using an AJAX search to pull 3 custom post types from wordpress (post, guides, advice). As you can see in my if while loop, the results show which results are which but I'm trying to section them out individually so it will show something like this:
section 1
blog posts
section 2
guides
The problem seems to be that I need to edit the if while loop because adding anything inside that loop will just cause it to be in that loop. Does anyone know the best way to modify the if while loop to achieve this?
function data_fetch(){
$the_query = new WP_Query(
array(
'posts_per_page' => 6,
's' => esc_attr( $_POST['keyword'] ),
'post_type' => array('post' , 'guides', 'advice'),
'post_status' => 'publish'
)
);
global $post;
if( $the_query->have_posts()) :
while( $the_query->have_posts() ): $the_query->the_post(); ?>
<?php $type = get_post_type();
$term = $_POST['keyword'];
$i++;
$total = $the_query->found_posts;
?>
<span class="search-title">
<?php if ($type == 'post'):?>
<?php echo 'Article: ';?>
<?php elseif($type == 'guide' ):?>
<?php echo 'Guide: ';?>
<?php elseif($type == 'advice' ):?>
<?php echo 'advice: ';?>
<?php endif;?>
<?php the_title();?><br>
</span>
<?php endwhile; ?>
<?php
wp_reset_postdata();
else:
echo '<h3>No Results Found</h3>';
endif;
die();
}
If I were you, I'd probably just do three separate queries. They seem simple enough that it shouldn't cause any issues at all. Otherwise you have to either sort through or reorder the WP_Query results somehow.
If you're set on the single query, however - since these are such short HTML strings, I'd probably just control the output with the Output Buffer.
Basically you can create an associative array, and add the HTML strings to the appropriate keys. You could get a bit more elaborate and have them be nested arrays, but since your output is so light, you can probably get by just by having HTML strings as the values for the keys.
I took the liberty of cleaning up your code a little bit and removing some unused variables, etc.
function data_fetch(){
// Build the Query Arguments
$the_query = new WP_Query( array(
's' => esc_attr($_POST['keyword']),
'posts_per_page' => 6,
'post_type' => array('post' , 'guides', 'advice'),
'post_status' => 'publish'
) );
// Do we have posts?
if( $the_query->have_posts()){
// We do. Start an array that will fill with HTML from the output buffer
$output = array(
'post' => '',
'guides' => '',
'advice' => '',
);
// Loop through the posts
while( $the_query->have_posts() ){
$the_query->the_post();
ob_start(); // Turn on the output buffer
$type = get_post_type(); ?>
<span class="search-title">
<?php echo ($type == 'post') ? 'Article: ' : ucwords($type).': '; // Output "Articles: " for posts, or just capitalize the other post type names ?>
<?php the_title();?><br>
</span>
<?php $output[$type] .= ob_get_clean(); // Add the HTML output from the buffer to our array
}
wp_reset_postdata();
// Here we have an array with 3 HTML strings that we can output wherever
echo $output['post'];
echo $output['guides'];
echo $output['advice'];
} else {
echo '<h3>No Results Found</h3>';
}
}
if I understood your concern, I propose to divide your code by creating a generic class.
and you make calls to the different Post Type :
class Custom_Query {
public $post_type;
public $key_word;
public function __construct($post_type, $keyword) {
$this->post_type = $post_type;
$this->key_word = $keyword;
}
public function getResult() {
echo '<h1>Article : ' . $this->post_type . '</h1>';
$the_query = new WP_Query(
array(
'posts_per_page' => 6,
's' => esc_attr($this->key_word),
'post_type' => array($this->post_type),
'post_status' => 'publish'
)
);
if ($the_query->have_posts()):
while ($the_query->have_posts()): $the_query->the_post();
echo '<span class="search-title">';
echo '' . the_title() . '<br>';
echo '</span>';
endwhile;
else:
echo '<h3>No Results Found</h3>';
endif;
wp_reset_postdata();
}
}
global $post;
$type = get_post_type();
$term = $_POST['keyword'];
$article = new Custom_Query($type, $term);
$article->getResult();
You were on the right track initially. You can just use the standard post objects to check for post type. You can adjust to fit your needs, but try something like this:
<?php
query = new WP_Query( array(
's' => esc_attr($_POST['keyword']),
'posts_per_page' => 6,
'post_type' => array('post' , 'guides', 'advice'),
'post_status' => 'publish'
) );
if ($query->have_posts()) {
while ($query->have_posts()):
$query->the_post();
?>
<div class="posts">
<?php
if ($query->post->post_type === 'post') {
// add your content
} else if ($query->post->post_type === 'guides' {
// add your content
} else {
// add your content
}
?>
</div>
<?php endwhile;
} else {
// no posts found
}

How to show post from just two categories on Wordpress Home page?

Only two categories need to be showed in the homepage. Can anyone help.
You can use WP_Query to get your posts list, and display it with the loop
Example :
$the_query = new WP_Query( array( 'category_name' => 'staff,news' ) );
// The Loop
if ( $the_query->have_posts() ) {
echo '<ul>';
while ( $the_query->have_posts() ) {
$the_query->the_post();
echo '<li>' . get_the_title() . '</li>';
}
echo '</ul>';
/* Restore original Post Data */
wp_reset_postdata();
} else {
// no posts found
}
In your functions.php file paste the below code:
I am assuming that you want to show categories from two categories which are having ids 5 and 9.
function kiran_home_category( $query ) {
if ( $query->is_home() && $query->is_main_query() ) {
$query->set( 'cat', '5,9');
}
}
add_action( 'pre_get_posts', 'kiran_home_category' );
Explanation:
kiran_home_category is just a custom name for the function. That can be any name. The way it works is you attach a function to the action hook pre_get_posts. So before getting the posts the function kiran_home_category will be called. And then inside the function I am changing the query here to only load categories with ID 5 and 9
In wordpress WP_query, category__in parameter used to select category with posts.
<?php
$query = new WP_Query( array( 'category__in' => array( 2, 6 ),'post_status'=>'publish','orderby'=>'menu_order','order'=>'Asc' ) );
if($query->have_posts()):
echo '<ul>';
while ( $query->have_posts() ) : the_post();
echo '<li>' . get_the_title() . '</li>';
endwhile;
echo '</ul>';
endif;
?>
For more information about wordpress query click here , you can read more information.
<?php
$args = array( 'post_type' => 'post', 'posts_per_page' => -1,'category_name' => array('Latest News','News') );
$loop = new WP_Query( $args );
if($loop->have_posts()):
?><ul>
<?php
while ( $loop->have_posts() ) : $loop->the_post();
?>
<li> <span class="date"><?php echo get_the_date( 'd F Y');?></span>
<h3><?php echo get_the_title();?></h3>
<?php echo $description = get_the_content(); ?>
</li>
<?php endwhile;?>
</ul>
<?php endif;?>
<?php wp_reset_postdata(); ?>
Do the following, usually in page.php or single.php or if you want a custom page for a category, you can do, category-samplecat.php..
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'category_name' => array('samplecat', 'anothercat'),
'paged' => $paged
);
$arr_posts = new WP_Query($args);
Then do the usual if, while statement..
if($arr_posts->have_posts() ) :
// Start the loop.
while ( $arr_posts->have_posts() ) :
$arr_posts->the_post();?>
<?php endwhile;
endif;

Woocommerce alphabetic list of products

I would like to have an alphabet listing the products by ABC... list
Something like
A | B | C | D .... Z
And that all link to the products-list sorted by their first letter.
I would like it placed above the list where the sorting dropdown menu is (top of the woocommerce ).
Is it possible somehow with coding, or is there some plug-in for it?
I put this at the end of orderby.php:
<div id="alphabet">
<?php
$args = array(
'post_type' => 'product',
'posts_per_page' => -1
);
$query = new WP_Query($args);
$by_letter = array();
while( $query->have_posts() ) { $query->the_post();
global $post;
$letter = substr($post->post_name, 0, 1);
if ( ! isset($by_letter[$letter]) ) $by_letter[$letter] = array();
$by_letter[$letter][] = $post;
}
wp_reset_postdata();
?>
<?php
if ( ! empty( $by_letter ) ) {
ksort($by_letter); // order the array
// fill the array with letters have no posts
$by_letter = fill_by_letter_array( $by_letter );
display_letters_anchors( array_keys( $by_letter ) );
foreach( $by_letter as $letter => $posts ) {
?>
<div id="Productlist_<?php echo strtoupper($letter); ?>" class="Productlist_<?php echo strtoupper($letter); ?>_object productlists">
<?php
if ( ! empty($posts) ) {
foreach ( $posts as $post ) {
setup_postdata($post);
// just an example of post output
echo '<p>' . get_the_title() . '</p>';
}
} else {
echo '<p>' . __('No products.') . '</p>';
}
?>
</div>
<?php
}
wp_reset_postdata();
}
?>
</div>
A bit of css, and it Works great!

Wordpress order posts by post type

I am trying to create a system which fetches post from 2 post types and i want to display the posts order by their post type. I am trying to first show the posts from one post type and then another post type but the query i used mixes it all. Can any one suggest a good solution for this. Here is my code.
$paged = get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1;
$args = array(
'post_type' => array('review','directory'),
'orderby' => 'name',
'order' => 'ASC',
'posts_per_page' => '4',
'paged' => $paged ,
'tax_query' => array( array(
'taxonomy' => 'Reviews',
'field' => 'id',
'terms' => $cat_id
), ),
);
query_posts($args);
if (have_posts()) :
while (have_posts()) : the_post();
$product_terms = wp_get_post_terms(get_the_ID(), 'Reviews', array("fields" => "all", "order" => "DESC"));
$postype=get_post_type( get_the_ID() );
if($postype=='review')
{
?>
<div class="review-post">
<h3><?php the_title(); ?></h3>
<div class="review-cat-new">
<?php echo get_the_term_list( $post->ID, 'Reviews', 'Category: ', ', ', '' ); ?>
</div>
<?php
if(get_field('see_it'))
$seeit_text= get_field('see_it');
if(get_field('skip_it'))
$skipit_text= get_field('skip_it');
?>
<div class="see-skip">
<p class="see-it"><span>See it:</span>
<?php echo $seeit_text; ?>
</p>
<p class="skip-it"><span>Skip it:</span>
<?php echo $skipit_text; ?>
</p>
</div>
<?php echo custom_field_excerpt(); ?>
</div>
<?php }
else
{
?>
<div class="review-post">
<h3><?php the_title(); ?></h3>
<div class="review-cat-new">
<?php echo get_the_term_list( get_the_ID(), 'Reviews', 'Category: ', ', ', '' ); ?>
</div>
<?php echo the_field('enter_content_direc'); ?>
<?php
if(get_field('enter_textdirec'))
$text= get_field('enter_textdirec');
if(get_field('enter_linkdirec'))
$textlink= get_field('enter_linkdirec');
?>
<div class="see-skip">
<p class="see-it direc"><span><a target="_blank" style="color:#5D6D71; text-transform: lowercase;" href="<?php echo $textlink;?>"><?php echo $textlink;?> </a></span>
</p>
</div>
</div>
<?php }
endwhile;
echo '<div class="paging">';
wp_pagenavi();
echo '</div>';
endif;
So is there a way so that i can first show the posts form reviews and then directory?
Since Wordpress 4.0 you can just pass the option type (post_type) to the orderby parameter in the WP_Query object.
orderby (string | array) - Sort retrieved posts by parameter. To order by post type just pass:
'type' - Order by post type (available since Version 4.0). ('post_type' is also accepted.)
As seen in the docs https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters , you can use the regular wp query by passing an array to 'orderby' :
$wp_query = new WP_Query(
array(
's' => $search,
'orderby'=> array('type'=>'DESC', 'title'=>'ASC'),
'paged'=>$paged
)
);
if ( $wp_query->have_posts() ) {
while ( $wp_query->have_posts() ) {
$wp_query->the_post();
// do your loop stufff here
}
}
Finally i got the solution and it can be done using a filter.
The solution looks like this.
add_filter( 'posts_request' , 'modify_request' );
function modify_request( $query) {
global $wpdb;
if(strstr($query,"post_type IN ('review', 'directory')")){
$where = str_replace("ORDER BY {$wpdb->posts}.post_date","ORDER BY {$wpdb->posts}.post_type",$query);
}
return $where;
}
Order per post types with custom post type order:
add_filter('pre_get_posts', function ($query) {
if ($query->is_search && !is_admin()) :
$query->set('post_type', [ 'cpt-1', 'cpt-2', 'post', 'cpt-3']);
endif;
return $query;
});
add_filter('posts_orderby', function ( $order ) {
if ( ! is_admin() ) :
if ( is_search() && is_main_query() ) :
global $wpdb;
$order = "FIELD( post_type, 'cpt-1', 'cpt-2', 'post' ), {$wpdb->posts}.post_modified DESC";
endif;
// Disable this filter for future queries!
remove_filter( current_filter(), __FUNCTION__);
endif;
return $order;
});
First solution which comes to my mind is to get posts only for first category. Reset query (wp_reset_query()) and get them again for second category. You need to double up your code of course, but I don't see any other solution - it's WordPress - you're very limited.
Second solution is to query database directly like this:
$result = mysql_query('SELECT *
FROM `wp_posts`
WHERE post_type = "page"
OR post_type = "post"
ORDER BY post_type ASC , post_date DESC ');
$posts = array();
if($result) {
while ($row = mysql_fetch_assoc($result)) {
$posts[] = $row;
}
}
mysql_free_result($result);
echo('<pre>');
var_dump($posts);
echo('</pre>');
die();
Notice that I've used post and page types as these are default, and exist in my WP installation. But you can use different. You can play with this query as much as you want.

Categories