I need to create an accordion list of news article titles grouped by year. So far the contents of the accordion panels are correct with each panel showing all of the news posts for that year.
The problem is that I'm getting multiple panels for years based on the number of articles for the year. So for example year 2003 has three news articles, so I'm getting three accordion panels for 2003, each with the three corresponding news articles for that year. For 2004 I get one accordion panel because there's only one article for 2004. 2006 has six articles so I get six panels each with the six articles inside.
What do I need to do to get only one panel with the correct number of titles inside?
Here's my SQL:
$newsposts = $wpdb->get_results("
SELECT YEAR(wp_posts.post_date) AS post_year, wp_posts.post_title, wp_posts.ID AS post_id
FROM wp_posts LEFT JOIN wp_term_relationships ON
(wp_posts.ID = wp_term_relationships.object_id)
WHERE wp_term_relationships.term_taxonomy_id = 3
AND wp_posts.post_status = 'publish'
ORDER BY post_date
", OBJECT );
Here's my markup:
<?php foreach($newsposts as $year) : ?> <?php //print_r($year); ?>
<li class="accordion-item" data-accordion-item>
<?php echo $year->post_year; ?>
<div class="accordion-content" data-tab-content>
<?php foreach($newsposts as $post) : ?> <?php //print_r($post); ?>
<?php // Continue unless years match
if ( $post->post_year != $year->post_year ) continue; ?>
<?php echo $post->post_title; ?><br/>
<?php endforeach; //$posts ?>
</div>
</li>
<?php endforeach; //$year ?>
</ul>
Somehow I need to limit the first foreach to only one for each year represented. I would appreciate any help.
I worked through this and found an answer thanks to this post:remove duplicates in foreach
In my case here is my revised markup:
<?php $yearposts = array(); ?>
<?php foreach($newsposts as $year) : ?> <?php $postyear = $year->post_year; ?>
<?php if(!in_array($postyear, $yearposts)) { ?>
<li class="accordion-item" data-accordion-item>
<?php echo $postyear; array_push($yearposts,$postyear); ?>
<div class="accordion-content" data-tab-content>
<ul class="accordlist">
<?php foreach($newsposts as $post) : ?>
<?php // Continue unless years match
if ( $post->post_year != $year->post_year ) continue; ?>
<li><a class="newstitle" href="<?php the_permalink($post->post_id); ?>"><?php echo $post->post_title; ?></a></li>
<?php endforeach; //$posts ?>
</ul>
</div>
</li>
<?php } // end in_array conditional ?>
<?php endforeach; //$year ?>
</ul>
As the indicated post says,
Basically we are just using an additional array to store the printed values. Each time we see a new value, we print it and add it to the array.
My version is broken into pieces to surround the elements that are required for the accordion formatting.
Anyway, I hope this helps someone else. I needed answers from different questions to find my solution. Now maybe someone will find everything in this one place.
Cheers
Related
I have the categories: 2D, 3D, Photo, Animation, which become buttons.
How can I skip the 3D and Animation from being displayed? on this particular page when running foreach. For example, the buttons that will appear have to be: All, 2D, Photo.
I tried to find a solution, but no luck.
What I managed to remove was only a string, but not multiple ones, with:
$key = array_search('3D',$terms);
unset($terms[$key]);
This is my code that I want to apply the changes to:
$terms = get_terms("portfolio_category",$cat_arguments);
if($terms):
?> <!-- category menu, this -->
<div class="row categories-p">
<ul class="col-sm-12">
<li><?php _e("All","um_lang"); ?></li>
<?php
sort($terms);
foreach($terms as $term):?>
<li>
<?php echo $term->name; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
You can use php's in_array, here's a basic example:
Assuming you have the following:
$categories = ['2D', '3D', 'Photo', 'Animation'];
And your skip list looks like this:
$skipList = ['3D', 'Animation'];
Then your render function will look like this:
iterate over category list
if the item is not in the skip list, render
foreach ($categories as $category) {
if (!in_array($category, $skipList)) {
// Display the category button
// e.g. echo "<button>{$category}</button>";
}
}
I'm using ACF plugin on my site. I want to sort my link containing date. So, in frontend I have something like that
01.10.2017, News
02.02.2018, News
06.09.2017, News
and I want it to be like that
02.02.2018, News
01.10.2017, News
06.09.2017, News
My code looks like this
<?php
$repeater = get_field('media');
$order = array();
foreach($repeater as $i => $row) {
$order[$i] = $row['media_date'];
}
array_multisort($order, SORT_ASC, $repeater);
if($repeater): ?>
<ol>
<?php foreach($repeater as $i => $row): ?>
<li>
<?php echo $row['media_date']; ?>, <a href="<?php echo
$row['media_link']; ?>" target="_blank"><?php echo $row['media_title']; ?>
</a>
</li>
<?php endforeach; ?>
</ol>
<?php else:
echo '<p>No matching post!</p>';
endif; ?>
And it sort data but incorrect. Incorrect I mean like this
01.10.2017, News
02.02.2018, News
06.09.2017, News
What I'm missing? How to order li items by date?
I’ve tried using GROUP BY in my query but that only returns one post per category. This is an example of what is returned with my current setup. What I need is for all posts with the same category to be grouped together, can someone point me in the right direction? Thanks for your time.
Like suggested by Charlotte, you could group your posts in an associative array, with the categories as keys.
<?php
// Connecting to database
$categories = array(); // Create an empty array
while ($post = mysqli_fetch_array($result)) {
if(!array_key_exists($post['category'], $categories)) { // Check if the category is already present
$categories[$post['category']] = array(); // Create an array indexed with the category name
}
$categories[$post['category']][] = $post; // Add the post to the category
}
?>
Now you have to iterate twice : to display the categories and to display each post in the category.
When I have to deal with nested foreach to render html, I preferably use inline foreach.
The rendering of the posts should look like :
<?php foreach ($categories as $category => $posts) : ?>
<h2><?php echo $category; ?></h2>
<?php foreach ($posts as $post) : ?>
<a href='article.php?id=<?php echo $post['post_id']; ?>' ><?php echo $post['title']; ?></a>
<p>Posted on <?php echo date('d-m-y h:i:s',strtotime( $post['posted'] ) );?> In <a href='category5.php?id=<?php echo $post['category_id']; ?>' ><?php echo $post['category']; ?></a>
</p>
<?php endforeach; ?>
<hr/>
<?php endforeach; ?>
Edit: I ometted the opening and closing php tags in the first block of code.
If you assemble the two blocks of code in your php file, it should work.
<ul>
<?php foreach (array_slice($items, 0, 3) as $item): ?>
<?php if (!isset($item->story)): ?> <!-- hide story updates -->
<li>
<?php if (isset($item->message)) echo $item->message; ?>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
I am displaying a news feed, and only want to display the items without a story update. So i am using !isset to check if a story item is present, and hide the item if it is.
This works perfectly, but now I am trying to display 3 results in the feed, but i think the story items are still being counted in the foreach, so when the last 3 updates are story items, nothing displays in the feed.
I have read this question which looks like what I am trying to do, but I dont understand where he has got the $elementkey variable from, and what it does?
How do I remove the item from the foreach, and remove its count so 3 items will display?
This should work for you:
(Here i just added a $count variable which i only increment if a message get's posted. And after 3 i break the foreach)
<ul>
<?php $count = 0;
foreach ($items as $item): ?>
<?php if ($count >= 3) break; if (!isset($item->story)): ?> <!-- hide story updates -->
<li>
<?php if (isset($item->message)) {
echo $item->message;
$count++;
}
?>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
I am having a little trouble trying to figure out how I can accomplish this: I have a container with two colums in it, a right and a left column. Each column will have 3 posts with a short excerpt stacked in it. Ideally I would like to add one into the right and one into the left until it reaches 3 rows of posts(although if that proves to be alot more of a difficult task than I am fine with posting to the first column than the second. I am able to loop through the posts and add them to one column, but I am having trouble figuring out how one will loop into two separate divs, without repeating the divs. Here is how I am attempting it, so far this code will loop into the left column.
The first left side is using the loop to display the title(excerpt will come after) and the right side is just using html. Can anyone help me figure this one out?
<h2>Popular posts</h2>
<h3>Showing the most popular posts.</h3>
<div class="col4 inner-left">
<ul class="popular-list">
<?php
query_posts('meta_key=post_views_count&orderby=meta_value_num&order=DESC&posts_per_page=10&post_type=pop');
if (have_posts()) : while (have_posts()) : the_post(); ?>
<li>
<a href=<?php the_permalink(); ?>><?php the_title(); ?></a>
<p>Popular post. This is a popular post, it really is.</p>
</li>
<?php
endwhile; endif;
wp_reset_query();
?>
</ul>
</div>
<div class="col4 inner-right">
<ul class="popular-list">
<li>
This is a popular post
<p>Popular post. This is a popular post, it really is.</p>
</li>
<li>
This is a popular post
<p>Popular post. This is a popular post, it really is.</p>
</li>
</ul>
</div>
You just need to apply logic for how you want the posts organized before you start iterating them.
Here's an example (this isn't functional, just a quick illustration):
<?php
$col1 = array();
$col2 = array();
$posts = array('one', 'two', 'three', 'four', 'five', 'six');
foreach ($posts as $post) {
$count++;
$count % 2 === 1 ? array_push($col1, $post) : array_push($col2, $post);
}
?>
<div class="col-1">
<?php
foreach ($col1 as $post) {
echo '<div class="post">'.$post.'</div>';
}
?>
</div>
<div class="col-2">
<?php
foreach ($col2 as $post) {
echo '<div class="post">'.$post.'</div>';
}
?>
</div>
This produces the output:
<div class="col-1">
<div class="post">one</div>
<div class="post">three</div>
<div class="post">five</div>
</div>
<div class="col-2">
<div class="post">two</div>
<div class="post">four</div>
<div class="post">six</div>
</div>
As you can see, now the elements of the $posts array are organized in both columns in an alternating fashion.