I have two fairly complex WordPress queries that I need to combine into a single query.
In my first query, I am getting Wordpress Posts by the date they are published. Each day of posts is contained inside a container, with the date showed above the posts as a title. It also only hides any posts that are in the past. Only posts from today or the future are shown.
In my second query, I am getting WordPress Posts from a Custom Taxonomy. For each term in the taxonomy, posts are displayed inside a container utilizing the slug of that term as a class, and displaying the name of the term as the title.
What I need to accomplish and what I need help with, is as follows.
I need the first query exactly as it is now, however, in the first query, where it says "// Need code here to display posts by taxonomy term //", I need to integrate the second query so that where posts are being output for that day, its also listing the posts by the term like in the second query.
Both queries function perfectly on their own, but I am having trouble with implementing a single query that utilizes the functionality from both queries to do what I need to do.
Here are my two queries:
1st Query:
<?php
// First we get yesterdays date
$year = date("Y"); $month = date("m"); $yesterday = date("d", strtotime("-1 day"));
// Then we construct a query to get items from the calendar, either published or scheduled for a future date so that they appear on the calendar. We use date query to hide events that have already passed by querying after the date we got before. We use yesterdays date to ensure that TODAYS post are still obtained
$query = new WP_Query(array('post_type' => 'calendar',
'post_status' => 'publish,future',
'orderby' => 'post_date',
'order' => 'DESC',
'date_query' => array(
array('after' => array(
'year' => $year,
'month' => $month,
'day' => $yesterday
)
)
)
));
// This is a special loop that gets posts by day and encases each days worth of posts in a container and shows the date of those posts. jQuery will be applied to this
if ($query->have_posts()) {
echo '<div class="day-posts">';
while ($query->have_posts()) {
$query->the_post();
echo '<div class="day">';
the_date('l jS F Y', '<div class="title"><div>', '</div>'); //Formats date, before echo, after echo
echo '<div class="posts clearfix">';
echo '<div class="post">';
the_title('<div class="title">', '</div>');
echo '<div class="content">';
// Need custom code here to display posts by taxonomy //
the_content();
echo '</div></div></div></div>';
}
echo '</div>';
}?>
2nd Query:
<?php
$post_type = array('calendar');
$tax = 'event-category';
$tax_terms = get_terms($tax, array('orderby' => 'id', 'order' => 'ASC'));
if ($tax_terms) {
foreach ($tax_terms as $tax_term) {
$args = array(
'post_type' => $post_type,
"$tax" => $tax_term->slug,
'post_status' => 'publish',
'posts_per_page' => - 1,
'caller_get_posts' => 1
); // END $args
$my_query = null;
$my_query = new WP_Query($args);
if ($my_query->have_posts()) {
echo '<div class="' . $tax_term->slug . '">';
echo '<div class="title">' . $tax_term->name . '</div>;
while ($my_query->have_posts()) : $my_query->the_post();
?>
<?php the_title();?>
<?php the_content();?>
<?php endwhile; echo '</div>'; } wp_reset_query(); } } ?>
I hope I have done a good job of explaining what I am trying to do. If I have not, or there are questions, please ask and I'll answer as quick as I can.
Ok here you go (I dont have posts setup like your query so i didn't test it but i believe this what you are looking for):
// Setup the basic structure:
$args = array(
'post_type' => 'calendar',
'post_status' => 'publish,future',
'orderby' => 'post_date',
'order' => 'DESC',
'date_query' => array(
array(
'after' => array(
'year' => $year,
'month' => $month,
'day' => $yesterday
)
)
),
'posts_per_page' => -1,
'caller_get_posts' => 1
);
// For dynamic taxonomy term create a bootstrap tax_query
$tax = 'event-category';
$tax_terms = get_terms($tax, array('orderby' => 'id', 'order' => 'ASC'));
if ($tax_terms) {
$args['tax_query'] = array(
array(
'taxonomy' => $tax,
'field' => 'slug',
)
);
// Append the slugs to the tax_query terms
foreach ($tax_terms as $tax_term) {
$args['tax_query'][0]['terms'][] = $tax_term->slug;
}
}
// Your One and only QUERY
$my_query = new WP_Query($args);
For $tax_term->slug and $tax_term->name you could use get_the_terms() within the query loop like:
$terms = get_the_terms($post->ID, $tax);
$terms = array_slice($terms, 0);
$term = $terms[0];
echo $term->slug;
echo $term->name;
EDITED
See code comments for explanation/clarification
if ($query->have_posts()) {
$_tax = false;
$same_date = array(); // collection of same dates
$same_date_bool = true; // determine previous post date exist
echo '<div class="day-posts">';
while ($query->have_posts()) {
$query->the_post();
$date = get_the_date('l jS F Y');
$same_date_bool = true;
// Checking if post is displayed from the current date
// then this post should be appended inside to previous
// opened div.day tag
if (!empty($same_date) && in_array($date, $same_date)) {
$same_date_bool = false;
}
// Collecting all dates
$same_date[] = $date;
// If post is not in same date
// create new div element
if ($same_date_bool) {
echo '<div class="day">
<div class="title">';
echo $date;
echo '</div>';
}
// If post is not in same date
// create new div element
if ($same_date_bool) {
echo '<div class="posts clearfix">';
}
echo '<div class="post">';
the_title('<div class="title">', '</div>');
echo '<div class="content">';
$terms = get_the_terms($post->ID, $tax);
// Note: I'm assuming your post will
// always have single term
$terms = array_slice($terms, 0);
$term = $terms[0];
if ($term) {
$_tax = true;
echo '<div class="' . $term->slug . '">';
echo '<div class="title">' . $term->name . '</div>';
}
the_content();
if ($_tax) {
echo '</div>';
}
echo '</div></div>';
// If post is in same date
// append closing div element for previous "div.day" element
if (!$same_date_bool) {
echo '</div></div>';
}
}
echo '</div>';
}
Hope this helps now. Also I have replaced the caller_get_posts with ignore_sticky_posts because caller_get_posts has been deprecated since v3.1
Related
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!
My code had a typo!
But im not allowed to delete this so here you have some info on ways you could have done a better job then me ;)
The problem is as follows, My query is skipping a part of my loop.
i have a query that makes a anchor with the title and thumbnail of the post.
it runs the query fine for the first post except for the second post it does not load in the thumbnail, but it does show the title, and the title is only mentioned after the thumbnail, There is no small image that resembles it cant be found either. My first question posted on here so apolagies for misplacing items in the wrong sections.
<?php
// WP_Query arguments
$args = array (
'post_type' => array( 'klantcase' ),
'post_status' => array( 'publish' ),
'nopaging' => true,
'order' => 'ASC',
'orderby' => 'menu_order',
);
// The Query
$klantcases = new WP_Query( $args );
// The Loop
if ( $klantcases->have_posts() ) {
while ( $klantcases->have_posts() ) {
$klantcases->the_post();
echo "<a href=".get_the_permalink().">";
echo get_the_post_thumbnail( null, $size = 'post-thumbnail');?><br><?php
echo the_title();?><br><?php
echo "</a>";
}
} else {
echo "no posts found";
}
// Restore original Post Data
wp_reset_postdata();
Now there is probably many ways to improve this loop but as mentioned im very new to all of this. That said i'd love to hear how you guys would resolve this issue.
Define empty variable on top of while loop.
And in loop concatenate your html with that empty variable.
For Example.
$output = '';
if ( $klantcases->have_posts() ) {
while ( $klantcases->have_posts() ) {
$klantcases->the_post();
$output .= '<a href="'.the_permalink().'">';
$output .= the_post_thumbnail() .'<br>';
$output .= the_title();
$output .= '</a>';
}
} else {
echo "no posts found";
}
echo $output;
You don't need to echo the_title() - it already echoes out, so I'm guessing that's where part of the problem is coming in. You can also make your loop a little more simple.
You don't need the 'post_status' argument, as publish is default.
In your loop, let's use WP's built in echo functions: the_permalink(), the_title() and the_post_thumbnail(). You don't have to pass any arguments to the the_post_thumbnail() because you are just calling the default in your code.
<?php
// WP_Query arguments
$args = [
'post_type' => ['klantcase'],
'nopaging' => TRUE,
'order' => 'ASC',
'orderby' => 'menu_order',
];
// The Query
$klantcases = new WP_Query( $args );
// The Loop
if ( $klantcases->have_posts() ) {
while ( $klantcases->have_posts() ) {
$klantcases->the_post(); ?>
<a href="<?php the_permalink(); ?>">
<?php the_post_thumbnail(); ?><br>
<?php the_title(); ?>
</a>
<?php
}
} else {
echo 'no posts found';
}
// Restore original Post Data
wp_reset_postdata();
I am using advanced custom fields pro to store and display information on estate sale dates. These are held in a repeater field, each row in the field has a start time, end time and a date. I need to display the information ordered by the date in the repeater field row. Currently it is ordered by date modified. I have tried several solutions but none seem to work for what I need to do.
This is what I have currently:
<?php
$latestes = new WP_Query(
array(
'post_type' => 'estate-sales',
'post_status' => 'publish',
'posts_per_page' => 10,
'orderby' => 'modified',
'order' => 'DESC'
)
);
while ( $latestes->have_posts() ) : $latestes->the_post();
echo '<li class="frontpage-esale"><a href="';
the_permalink();
echo '">';
the_title();
echo ' ';
$rowses = get_field('estate_sale_dates');
$first_row = $rowses[0];
$first_row_date = $first_row['es-date'];
$first_row_start = $first_row['es-start-time'];
$first_row_end = $first_row['es-end-time'];
echo ' - ';
if ($first_row_date) {
echo date('F j, Y',strtotime($first_row_date));
}
else {
echo 'Sale Dates TBA';
}
endwhile;
wp_reset_query();
?>
The most common answer when searching for a solution is to do something like this:
$latestes = new WP_Query(
array(
'post_type' => 'estate-sales',
'post_status' => 'publish',
'posts_per_page' => 10,
'orderby' => 'modified',
'order' => 'DESC'
)
);
while ( $latestes->have_posts() ) : $latestes->the_post();
$repeater = get_field('estate_sale_dates');
foreach( $repeater as $key => $row )
{
$column_id[ $key ] = $row['es-date'];
}
array_multisort( $column_id, SORT_ASC, $repeater );
foreach( $repeater as $row ) {
echo '<li class="frontpage-esale"><a href="';
the_permalink();
echo '">';
the_title();
echo ' ';
$rowses = get_field('estate_sale_dates');
$first_row = $rowses[0];
$first_row_date = $first_row['es-date'];
$first_row_start = $first_row['es-start-time'];
$first_row_end = $first_row['es-end-time'];
echo ' - ';
if ($first_row_date) {
echo date('F j, Y',strtotime($first_row_date));
}
else {
echo 'Sale Dates TBA';
}
}
endwhile;
wp_reset_query();
?>
However, when I try that, it lists each sale 3 times, does not order by the date at all, and if no date is entered (which needs to just default to Sale Dates TBA) it throws an error.
Any help greatly appreciated.
Note, that your integration isn't complete, signaled by having two get_field('estate_sale_dates');, and the name $first_row being out of place when iterating all of them. Without the sort, you're basically doing
$repeater = get_field( 'estate_sale_dates' );
...
foreach ( $repeater => $row_that_isnt_used )
{
$rowses = get_field( 'estate_sale_dates' );
$first_row = $rowses[0];
}
I think something like this is what you're after:
<?php
while ( $latestes->have_posts() ) {
$latestes->the_post();
echo '<li class="frontpage-esale"><a href="';
the_permalink();
echo '">';
the_title();
echo '</a> ';
if ( ! count( $sale_dates = get_field('estate_sale_dates') ) )
echo '<span>Sale Dates TBA</span>';
else
{
// $order = array_column( $sale_dates, 'es-date' ): (php 5.5+)
foreach( $sale_dates as $ignore => $row )
$order[] = $row['es-date'];
array_multisort( $order, SORT_ASC, $sale_dates );
echo "<ul>";
foreach( $sale_dates as $row ) {
$date = $row['es-date'];
$start = $row['es-start-time'];
$end = $row['es-end-time'];
echo "<li>" . date('F j, Y',strtotime($row_date)) . " $start-$end</li>";
}
echo "</ul>";
}
echo "</li>";
}
I have the same problem with a calendar. There is no solution to do this in the right way with a repater field. The best way to do this, is to use an custom field in an hidden post type and a relation field.
Because any PHP solution is inperformant.
Make a Custom Post Type "Sales Dates" an in this a custom field "date" and a second "Post Relation".
Then select from Post Type "Sales Dates" all Posts order by meta key "dates" with the relation field you get the data from the not hidden post type.
Well...the problem is that ... Ess. Grid is not showing up in posts for a one page. It's a custom made template. Maybe there is something wrong with my post loop. Maybe there is something wrong with my jquerys.
The loop
case 'gallery':
$a_div_st = '<div id="';
$cat_name = $category->name;
$a_div_st_e = '" class="container-fluid">';
$a_div_end = '</div>';
$g_args = array(
'category_name' => 'gallery',
'post_type' => 'post',
'orderby' => 'date',
'order' => 'ASC',
);
$gallery = new WP_Query($g_args);
if($gallery->have_posts()){
echo $a_div_st.$cat_name.$a_div_st_e;
while($gallery->have_posts()){
$gallery->the_post();
echo '<h1>';
the_title();
echo '</h2>';
the_content();
}
wp_reset_postdata();
echo $a_div_end;
}
break;
Sorry for the unorganized code. I have never made WP templates.
I have a Custom post type of "events" and I have a custom metabox for the date of the event. All events added with all dates recorded into database in srtotime() UNIX format.
When list of events is queried I need to separate them by week. So.. "week of 4/23" then list the events for that week only.. followed by "Week of 4/30" with the events for that week listed.
All of this needs to be dynamic and logically detect when each week begins and compare that to the date that is saved in the database for the returned events, thus grouping them into "weeks."
I hope that all makes sense. I am just having trouble finding resources for this type of functionality, and I am uncertain of the logic needed and what WP might already have I could use.
As of now the results are being pulled using a custom Wordpress loop, but I could use SQL if needed.
Thanks in advance for helping any way you can!
*UPDATED CODE
<?php
$loop = new WP_Query(array(
'post_type' => 'tf_events',
'posts_per_page' => -1,
'orderby' => 'meta_value',
'meta_key' => 'tf_events_startdate',
'order' => 'ASC'
));
echo '<pre>';
print_r($loop);
echo '</pre>';
$groups = array();
if ($loop->have_posts()) {
while ($loop->have_posts()) {
$loop->the_post();
$groups['Week of ' . $post->post_date][] = $post;
// Get event dates from WP metabox data (returns as string)
$longstartdate = get_post_meta($post->ID, 'tf_events_startdate', true); //get start date meta data
$longenddate = get_post_meta($post->ID, 'tf_events_enddate', true); //get start date meta data
$longweekof = get_post_meta($post->ID, 'tf_events_weekof', true); //get Week Of date meta data
// Reformat dates
$prettystartdate = date("D. M. j, Y", $longstartdate);
$prettyenddate = date("l, F j, Y", $longenddate);
$prettyweekof = date("m/d", $longweekof);
// Get Custom Meta Terms/Catagories/taxonomies
$the_venue = get_the_term_list( $post->ID, 'venue' );
$event_age = get_the_term_list( $post->ID, 'event_age' );
// Get Custom Metabox Data - URL for Buy Tickets
$buytix = get_post_meta( $post->ID, 'buytix', true );
}
}
?>
<h1>Groups of posts</h1>
<?php echo '<pre>'; print_r($groups); echo '</pre>';?>
<?php foreach ($groups as $week => $rows) : ?>
<h2><?php echo $week ?></h2>
<ul>
<?php foreach ($rows as $post) : setup_postdata($post) ?>
<?php echo ' <h1>POST START</h1> <pre>';
print_r($post);
echo '</pre> <h1>POST END</h1>'; ?>
<li><?php the_title() ?> <?php echo $prettystartdate; ?></li>
<?php endforeach ?>
</ul>
<?php endforeach ?>
When I need to group elements I normally use an associative array where the key is the thing to group by. So in your case the array would look something like:
array(
'Week of 4/30' => array(array of posts)
);
An easy way to do this (once you have all the posts) is like this:
$groups = array();
foreach ($posts as $post) {
$groups['Week of ' . date('m/d', $post->pub_date)][] = $post;
}
And then you can just:
foreach ($groups as $title => $posts) {
echo "<h2>$title</h2>";
foreach ($posts as $post) ...
}
Edit: Here's what a more complete code (including WP query etc) would look:
<?php
# Get all posts
$loop = new WP_Query(array(
'post_type' => 'tf_events',
'posts_per_page' => -1,
'orderby' => 'meta_value',
'meta_key' => 'tf_events_startdate',
'order' => 'ASC'
));
$groups = array();
# Create groups of posts
if ($loop->have_posts) {
while ($loop->have_posts()) {
$loop->the_post();
$groups['Week of ' . date('m/d', $post->tf_events_weekof)][] = $post;
}
}
?>
<h1>Groups of posts</h1>
<?php foreach ($groups as $week => $rows) : ?>
<h2><?php echo $week ?></h2>
<ul>
<?php foreach ($rows as $post) : setup_postdata($post) ?>
<li><?php the_title() ?></li>
<?php endforeach ?>
</ul>
<?php endforeach ?>
Here is rough solution that is working for me.
<?php
$loop = new WP_Query(array(
'post_type' => 'tf_events',
'posts_per_page' => -1,
'orderby' => 'meta_value',
'meta_key' => 'tf_events_startdate',
'order' => 'ASC'
));
$groups = array();
$heading = '';
if ($loop->have_posts()) {
while ($loop->have_posts()) {
$loop->the_post();
//set up pretty week
$weekof = get_post_meta($post->ID, 'tf_events_weekof', true); //get Week Of date meta data
$longstartdate = get_post_meta($post->ID, 'tf_events_startdate', true); //get start date meta data
$longenddate = get_post_meta($post->ID, 'tf_events_enddate', true); //get start date meta data
//format dates
$prettyweekof = date("m/d", $weekof);
$prettystartdate = date("D. M. j, Y", $longstartdate);
$prettyenddate = date("l, F j, Y", $longenddate);
//set info on objects
$post->prettyweekof = $prettyweekof;
$post->pretty_startdate = $prettystartdate;
$post->pretty_enddate = $prettyenddate;
//Echo heading when need to
if($post->prettyweekof !== $heading)
{
$heading = $post->prettyweekof;
echo '<h2>'.$heading.'</h2>';
}
//list events
echo $post->post_title.' | '.$post->pretty_startdate.' - '.$post->pretty_enddate.'<br />';
}
}
?>