I have the following loop in Wordpress and even though it always worked (at least, I think so), it recently stopped working as it should:
<?php
$items = 0;
$thiscat = get_category(3);
$cat_slug = $thiscat->slug;
$args = array(
'post_type' => 'Course',
'posts_per_page' => 3,
'meta_key' => 'date_start',
'orderby' => 'meta_value',
'category_name' => $cat_slug,
'order' => 'ASC',
); ?>
<ul>
<?php
$loop = new WP_Query( $args );
while ( $loop->have_posts() AND $items < 3) {
$loop->the_post();
$category_course = get_the_category(3);
global $post;
$category_detail = get_the_category( $post->ID );
$date_start = get_post_meta(get_the_ID(), 'date_start', true);
$place = get_post_meta(get_the_ID(), "place", true);
if( $date_start >= strtotime('today') ) { ?>
<li>
<?php echo strftime("%a, %e. %b. %Y", $date_start); ?> - <?php echo $place;?>
<?php foreach ($category_detail as $category_ID)
{
if($category_ID->cat_name == 'z_aflyst')
{
echo "- <strong>Aflyst</strong>";
}
}?>
</li>
<?php $items++; }
}
if($items==0) { ?>
<li>
Ingen kommende kurser
</li>
<?php } ?>
The expected result: Count all courses that are to be held in the future, display a maximum of 3 on the front page
The outcome: Count all courses that are in the database (both past and present) with a maximum of 3, display the ones to be held on the front page (the ones held in the past are not displayed, but are counted). If 3 or more courses held in the past, it doesn't display any of the courses to be held in the future.
In my head, it should be ignoring all posts with a date from before today, but it apparently still counts them, as the output on the front page is only one course (in the case of the above loop, where there are two courses held in the past and three planned for the future), instead of the available 3. I found out that if I change the posts_per_page to 4, it'll display one more course, so it really has to do with the fact that it also counts the courses in the past as a post in the posts_per_page.
It's probably just a small tweak of my code, but how and where do I make sure it ignores posts from before strotime('today')?
By adapting my $args's meta-query, I managed to compare the value of the meta-key with a value of my choosing (in my case time()).
By adding this, it was even possible to remove my if-sentence where I would find out if a course was placed in the future or past.
$args['meta_query'] = array(
array(
'key' => 'date_start',
'value' => time(),
'compare' => '>='
)
)
This results in the $args variable only grabbing posts that are equal or greater than time(). Epic solution thanks to StackOverflow, as it even made my code more readable.
Related
I have the WordPress site below that displays a map of medical providers and a list below that of those same providers.
https://preview.scmamit.yourmark.com/?sfid=756&_sft_provider_type=primary-care
I need to show all of the results of a search on the map, but then the list should have pagination (only displaying 25 per page). I'm running through the loop twice, 1st to build the pins for the map, and 2nd to display the list.
If I turn off pagination to show all the pins on the map, how then would I display the list with pagination below the map?
Back in my Coldfusion days, I would have done a query of queries for the 2nd loop, and I've seen "pre_get_posts" and some other options that seem close to what I want, but nothing is quite getting me there.
Just run the loop a 2nd time:
First reset the 1st query at the end of it:
wp_reset_query();
And add this to your second query:
$count = get_option('posts_per_page', 10);
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$offset = ($paged - 1) * $count;
And add this args to the query:
'posts_per_page' => $count,
'paged' => $paged,
'offset' => $offset,
Regards Tom
Thought I would post what I did to get this work. Thanks to #tom-ukelove for getting me headed in the right direction.
I had the map, list and search filter on this page. The search filter is created with Search & Filter plugin.
https://scmamit.com/?sfid=756
In my Search & Filter settings, I set the results per page to 25, which is what I needed the list to do in loop #2.
To display all of the results on the map (loop #1), I used the following code to remove the 25 posts_per_page limit.
<?php
//get the search variables from URL
$this_keyword = $_GET['_sf_s'];
$this_provider_type = $_GET['_sft_provider_type'];
$this_city = $_GET['_sfm_city'];
//rebuild the query
$args = array(
'post_type' => 'providers',
'provider_type' => $this_provider_type,
's' => $this_keyword,
'meta_query' => array(
array(
'key' => 'city',
'value' => $this_city,
'compare' => 'LIKE'
)
),
//use -1 to remove the 25 results per page limit
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC'
);
$the_query = new WP_Query( $args );
global $wp_query;
// Put 25 limit query object in a temp variable
$tmp_query = $wp_query;
// Now purge the global query
$wp_query = null;
// Re-populate the global with the no-limit custom query
$wp_query = $the_query;
$count = $the_query->post_count;
//run the loop #1 and build map pins within.
while($the_query->have_posts()) : $the_query->the_post();
//echo out map pin code here, or whatever you need in the 1st loop.
endif;
endwhile;
//reset the query
wp_reset_query();
// Restore original 25 limit query object
$wp_query = null;
$wp_query = $tmp_query;
?>
<ul>
<?php
// run the 2nd loop with pagination
while(have_posts()) : the_post();
// some <ul> list here
endwhile;
?>
</ul>
<?php
//display pagination
$numeric_posts_nav();
?>
Hope that helps someone in the future. Lmk if there's a more efficient way to do it.
I have a CPT called Classes. Via an ACF Relationship field I'm allowing my client to hand pick classes to show on the front end. Each class has an expiry date.
Within a foreach statement I set up a conditional that compares the current date with the expiry date and only shows upcoming classes. What I need is to show a single note saying "there are no upcoming classes" once all the selected classes have gone past their expiry date.
ACF support suggested adding an incremental operator within the foreach loop and then checking if that value is empty. They modified my code as follows but it doesn't do the job. Additional help from ACF support falls outside the scope of what they offer, so I'm posting here for guidance. Thanks!
<?php
$all_classes = get_sub_field('class');
if( $all_classes ):
?>
<?php
$i = 0;
foreach($all_classes as $post):
setup_postdata($post);
?>
<?php
$now = time(); // get today's date
$expiry_date = strtotime(get_field('class-expiry-date')); // get the expiration date
if ($now < $expiry_date): // compare the dates and show upcoming classes only
$i++;
?>
class details
<?php endif; ?>
<?php
endforeach;
wp_reset_postdata();
?>
<?php else: ?>
<?php
//check if $i is empty
if(empty($i)):
?>
There are no upcoming classes.
<?php endif; ?>
<?php endif; ?>
Iv'e ran into this many times. My approach is a little different. Is use a normal WP_Query() and make sure the ACF relationship postobject field not saving the handpicked items as post object but as an post ID. (this is just an option to select on the custom field page). In this way I can make use of the native Wordpress meta queries
My args array is as follows allowing the query to sort on an specific date field that is equal or newer than today.
$args = array(
'post_type' => 'class', /* (your CPT slug: class or classes) */
'posts_per_page' => -1,
'meta_key' => 'class-expiry-date',
'orderby' => 'meta_value',
'order' => 'ASC',
'post__in' => array( get_sub_field( 'class' ) ),
'meta_query' => array(
array(
'key' => 'class-expiry-date',
'value' => date('Ymd', strtotime('now')),
'type' => 'date',
'compare' => '>=',
)
)
);
$wp_query = new WP_Query( $args );
if( $wp_query->have_posts() ) {
while( $wp_query->have_posts() ) {
$wp_query->the_post();
// Upcoming classes !!
// echo $post->post_title (example)
}
} else {
// There are no upcoming classes
}
wp_reset_query();
Make sure you output the custom expiry date field in the following
format Ymd (also an option on the custom fields page)
I have found this question:
Wordpress outside loop sort by category and time
But there is not a lot of context provided in the question or answer to know if it is applicable to me. I am using the popular genesis framework and a child theme. I don't want to modify any core WP files because they would be overwritten on updates. I think this can be done through my functions.php or front-page.php file.
I have 25 posts listed at a time. Within those 25 posts, I would like to have any post that is from category one be listed on top and those from category two listed afterwards. Within the category one and category two loops, the posts would be listed by time of entry as normal.
What would be the best way to do this?
SDS
You need two loop one for categories and one for posts.
So you can try this type of code
/*category args for listed according to name in assending order*/
$category_arg = array(
'orderby' => 'name',
'order' => 'ASC'
);
$all_cat = get_categories($category_arg);
/*Loop for all category*/
foreach ($all_cat as $key => $cat) {
/*Query for post of perticular category with orderby posted date*/
$args = array(
'cat' => $cat->cat_ID,
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'DESC',
) ;
query_posts( $args );
echo '
<div class="one-category-block">
<h1>'.$cat->cat_name.'</h1>';
echo '<ul>';
while ( have_posts() ) : the_post();
echo '<li>';
the_title();
echo '</li>
';
endwhile;
echo '</ul>
</div>';
wp_reset_query();
}
Try this type of code , then let me know the result.
Thanks
All right. You won't be able to do that on the query directly, I'm afraid.
However, it's still easy to do. First, get the posts out of the query into an array:
$posts = array();
while ( have_posts() ) {
the_post();
array_push($posts, $post);
}
Then sort that array:
usort($posts, function($a, $b) {
if(has_term("mycategory", "mytaxonomy", $a->ID) && !has_term("mycategory", "mytaxonomy", $b->ID)) return -1;
if(!has_term("mycategory", "mytaxonomy", $a->ID) && has_term("mycategory", "mytaxonomy", $b->ID)) return 1;
return $b->post_date - $a->post_date;
});
I've made it so that posts having mycatgegory in the mytaxonomy taxonomy will be on top, but generally sorted by post date.
Then just use a regular foreach loop to iterate over the (now sorted) posts
foreach($posts as $post) {
setup_postdata($post);
// continue outputting the posts here
}
wp_reset_postdata();
setup_postdata() is there to make sure that you can use get_the_ID(), get_permalink() et cetera without changing your code.
I want to loop through two different custom post types to find out what should be displayed. In CPT project I want to now the name of the house, in CPT portfolio I want to know the category. If these two are the same, I want a certain content from the project CPT to be shown.
On this page you're on the single-portfolio.php.
The code below have two errors (at least) the first one is that all the projects house types ($houseType) displays for no reason and the second one is that the content within the second loop doesn't display at all.
So, to try to make this a bit more clear:
I want to display the name and the city of the project which house type name matches the portfolio category (which is the name of the house type)
$args = array('post_type' => 'project');
$my_query = new WP_Query( $args );
if( $my_query->have_posts()) while ($my_query->have_posts()) : $my_query->the_post();
$houseType = the_field('hustyp');
$argsPort = array(
'post_type' => 'portfolio',
'tax_query' => array(
array(
'taxonomy' => 'portfolio_category',
'field' => 'slug', //can be set to ID
'terms' => $houseType
)));
$port_query = new WP_Query($argsPort);
if( $port_query->have_posts()) while ($port_query->have_posts()) : $port_query->the_post(); ?>
<tr>
<td><?php the_field('brf')?>/<?php the_field('ort')?></td>
</tr>
<?php
endwhile;
?>
<?php
endwhile;
I don't know if the best way to go is by creating an own query or something like that.
Any ideas?
UPDATE
Okay, I made some progress and finally realized that the_field displays the field and therefor I should use get_field. But I still don't know how to compare the two different post types to see if it is a match, and after that display only the matches. I'm thinking that creating an array can be a solution, but don't know how to go forward. As you can see in my new code below.
New code:
$args = array(
'post_type' => array( 'portfolio', 'project' ));
$my_query = new WP_Query( $args );
if( $my_query->have_posts()) {
while ($my_query->have_posts()) : $my_query->the_post();
//Returns All Term Items for "my_taxonomy"
$term_list_portfolio = wp_get_post_terms($post->ID, 'portfolio_category', array("fields" => "all"));
// Just get the category
$category = $term_list[0]->name;
// Get the house type
$houseType = get_field('hustyp');
$result = array($term_list[0]->name, get_field('hustyp'));
print_r($result);
if($category == $houseType) { ?>
<tr>
<td><?php the_field('brf')?><?php the_field('ort') ?>
<?php }
endwhile;
}
Try to reset query <?php wp_reset_query(); ?> before second wp_query reffer
I have two WordPress post types the normal 'post' and a custom post type called 'notes'. I want to combine both and sort them by date. I managed to find the combine query and that's working fine. The problem is I'd like to have different styling for notes. I thought I could do a wordpress if_singlular('notes') to try and target it.. but I'm guessing it's getting lost when the merge happens.
Does anyone know how I could achieve this functionality?
Many thanks!
My php:
<?php
// An example of creating two separate WP queries, combining the results,
// sorting by date and formatting the results for us in a loop like a regular query.
// order the posts by date in descending order (should go in functions.php to keep things tidy)
function order_by_date( $a, $b )
{
return strcmp( $b->post_date, $a->post_date );
}
// get the posts for the first query
$q1_args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'publish'
);
$q1_posts = get_posts( $q1_args );
// get the posts for the second query
$q2_args = array(
'post_type' => 'notes',
'posts_per_page' => -1,
'post_status' => 'publish'
);
$q2_posts= get_posts( $q2_args );
// Merge the post arrays together, and sort by date using the order_by_date function
$final_posts = array_merge( $q1_posts, $q2_posts );
usort( $final_posts, 'order_by_date' );
// Loop over the posts and use setup_postdata to format for template tag usage
foreach ( $final_posts as $key => $post ) {
setup_postdata( $post );
// Now we can use template tags as if this was in a normal WP loop
foreach ( $final_posts as $key => $post ) {
setup_postdata( $post );
// Now we can use template tags as if this was in a normal WP loop
echo '
<article class="item shortNote">
<div class="snMeta clearfix">
<img src="'.get_bloginfo('template_url').'/assets/images/sn-icon.png" alt="Short Note" />
<span class="metaDate">'. get_the_date('M / d / Y').'</span>
<strong>Short Note</strong>
</div>
<h2>'.get_the_title().'</h2>
</article>';
}
}
?>
Ok so this should do it:
<?php
// An example of creating two separate WP queries, combining the results,
// sorting by date and formatting the results for us in a loop like a regular query.
// order the posts by date in descending order (should go in functions.php to keep things tidy)
function order_by_date( $a, $b ) {
return strcmp( $b->post_date, $a->post_date );
}
// get the posts for the first query
$q1_args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'post_status' => 'publish'
);
$q1_posts = get_posts( $q1_args );
// get the posts for the second query
$q2_args = array(
'post_type' => 'notes',
'posts_per_page' => -1,
'post_status' => 'publish'
);
$q2_posts= get_posts( $q2_args );
// Merge the post arrays together, and sort by date using the order_by_date function
$final_posts = array_merge( $q1_posts, $q2_posts );
usort( $final_posts, 'order_by_date' );
// Loop over the posts and use setup_postdata to format for template tag usage
foreach ( $final_posts as $key => $post ) {
$post_type = $post->post_type;
setup_postdata( $post );
// Now we can use template tags as if this was in a normal WP loop
<article class="item shortNote ' . $post_type . '">
<div class="snMeta clearfix">
<img src="'.get_bloginfo('template_url').'/assets/images/sn-icon.png" alt="Short Note" />
<span class="metaDate">'. get_the_date('M / d / Y').'</span>
<strong>Short Note</strong>
</div>
<h2>'.get_the_title().'</h2>
</article>';
}
?>
I just had to test it on my server to see if it works. So I added the $post_type variable that should return the post type, and then I just put that in your class in the <article> tag, so you can differentiate :)
Tip:
When in doubt what your loop outputs, always do print_r(). This will show you what you are dealing with (arrays, strings, objects) so you easily know what to target :)
Hope this helps.