Reset variable at each iteration of PHP foreach loop - php

I'm essentially using a foreach loop to loop through some post categories and then output some markup for the posts in each category. I thought my variable $ii would get reset at each iteration of the foreach, but it caries over (silly assumption on my part). I do need $ii=1 at the beginning of each loop, is there a way to accomplish this? Basic code structure below
$cats = array(
'cat1' => 20,
'cat2' => 21,
'cat3' => 22,
'cat4' => 23
);
foreach($cats as $cat){
$ii = 1;
$cat_name = get_cat_name($cat);
echo "<div class='container'>
<h1>$cat_name</h1>
";
while( have_posts() ) : the_post();
$title = get_the_title() . ' ' . $ii;
if( in_category($cat) ){
echo "<p>$title</p>";
}
$ii++; endwhile;
echo '</div>'; // end container
}
For three posts in each category, what's being outputted is, essentially:
Cat1
- title 1
- title 2
- title 3
Cat2
- title 4
- title 5
- title 6
etc.
My desired output is:
Cat1
- title 1
- title 2
- title 3
Cat2
- title 1
- title 2
- title 3
Is there a way to reset the variable for each iteration to achieve my desired output? Or a better way to do this? Haven't been able to find anything on it yet. Seems pretty simple, though. Thank you in advance!
EDIT:
A bunch of the answers on here got something working, but scoping the counter to a condition helped me solve the issues I needed. Kind of a workaround, but I basically just needed to check if I was on the 5th iteration of the while loop in a specific category to output a certain block of markup for a special case. (Sorry if the way I posed the question left my objective a little bit ambiguous, there's a lot going on in the actual loops I'm running - I wanted to keep it as simple as possible.) So, as of now, the workaround looks like so:
if( $cat == $cats['cat2']){
$ii++;
if($ii === 5){
echo '<hr>';
}
}
Still feel like there's a more robust way of accomplishing this and I'm open to new ideas for it, but it's working for now!

Not sure what's going on inside those functions of yours but try building your $title variable inside your in_category() condition check
if (in_category($cat)) {
$title = get_the_title() . ' ' . $ii;
echo "<p>$title</p>";
$ii++;
}
It looks like your functions for grabbing posts are re-grabbing every post again and only outputting the ones you need based on the value of $cat, via in_category(). Your $ii counter should be resetting just fine since you are explicitly setting it to 1 at the beginning of each foreach iteration.

You could increment a different counter inside the while loop then increment the other counter after the while loop ends:
$counter = 1;
while( have_posts() ) : the_post();
$title = get_the_title() . ' ' . $counter;
if( in_category($cat) ){
echo "<p>$title</p>";
}
$counter++;
endwhile;
$ii++;

Related

Wordpress multiple loops and general loop

I need creating custom multiple loops for my blog home.php in order to show 3 different content layout of defined category then proceed with the general loop excluding posts ID within the first 3 loops.
So far I made the the 3 different content layout of defined category category_name=arts:
<?php $posts = get_posts('numberposts=1&offset=0'); foreach ($posts as $post) : start_wp(); ?>
<?php static $count1 = 0; if ($count1 == "1") { break; } else { ?>
<?php the_title(); ?>
<?php $count1++; } ?>
<?php endforeach; ?>
<?php query_posts('category_name=arts&showposts=1'); ?>
<?php $posts = get_posts('numberposts=1&offset=1'); foreach ($posts as $post) : start_wp(); ?>
<?php static $count2 = 0; if ($count2 == "1") { break; } else { ?>
<?php the_title(); ?>
<?php $count2++; } ?>
<?php endforeach; ?>
<?php query_posts('category_name=arts&showposts=1'); ?>
<?php $posts = get_posts('numberposts=1&offset=2'); foreach ($posts as $post) : start_wp(); ?>
<?php static $count3 = 0; if ($count3 == "1") { break; } else { ?>
<?php the_title(); ?>
<?php $count3++; } ?>
<?php endforeach; ?>
I did get stuck to proceed with the general loop. Any suggestions are much appreciated.
You have serious issues here
For each loop you are running two queries, one withget_posts() and one with query_posts
You are making use of query_posts which you should never ever use. This adds a huge overhead on your query as you rerun the main query, so you are actually running 3 queries to get 1 post for each loop. This slows your page down which costs you dearly when it comes to SEO
Furthermore, query_posts breaks the main query object which breaks thousands of functions an plugins that relies on the main query object. You should really spent time and read this post on just how really bad query_posts is.
start_wp() was already depreciated in WordPress version 1.5. This means your code has bugs, and one should avoid bugs at all costs. You should really turn on debug while developing as debug will immediately throw a debugging message telling you that you are using a depreciated function. Here is an article from the codex on how to work with the debugging feature in WordPress. You should be using setup_postdata( $post )
Still on the debugging part, showposts was dropped in favor of posts_per_page
You are running a foreach loop without making sure you have posts to display. ALWAYS ALWAYS make sure you have valid values before you try to do anything with a dynamic variable. This will avoid numerous bugs should your variable return an empty value.
You should really work on your formatting as your code is quite hard to read when everything is packed into one line. Use proper indentation. Properly indented and formatted code does help a lot with readability and debugging. Also, drop the : and endforeach syntax. Although it is valid, it is not supported by code editors which make debugging a nightmare should your code fail. I always tell everyone to use the old style curly brackets as all code editors support them. They make debugging very easy
ALWAY ALWAYS, VERY IMPORTANT, always reset custom queries. Use wp_reset_postdata() to reset the $post global whenever you call setup_postdata() or the_post() in a custom query. Just for interest, because I have already stated to never use query_posts, you should use wp_reset_postdata() to reset custom queries created with query_posts
Lastly, you can do what you need with the specified category in only one loop, not three. Simply make use of your counters. If this is purely for styling, you can simply use the :nth child() selector in css3
The following is untested, but you can try the following
$special_cat_args = [
'category_name' => 'art',
'posts_per_page' => 3,
//Add extra arguments here
];
$art_posts = get_posts( $special_cat_args );
// Setup a variable to store the post ID's so we can exclude them in the 'main' query
$ids_array = [];
// Check if we have posts before we continue
if ( $art_posts ) {
// Start our counter
$counter = 0;
// Start the loop
foreach ( $art_posts as $post ) {
// Setup postdata, must use $post
setup_postdata( $post );
// Store the post id in an array to exclude in "main" query
$ids_array[] = $post->ID;
// Do something separate for every post
if ( 0 == $counter ) {
// Do something for post one
} elseif ( 1 == $counter ) {
// Do something for post two
} elseif ( 2 == $counter ) {
// Do something for post three
}
// Update the counter
$counter++;
} //endforeach $art_posts
wp_reset_postdata(); // VERY VERY IMPORTANT
} //endif $art_posts
// Now we can do our "main" query and exclude the three posts from the special category
$args = [
'post__not_in' => $ids_array, // Exclude the three post from previous query
// Rest of your arguments
];
$q = get_posts( $args );
// Run your loop

Start index numbering at 1 (not 0) with $key

I've got a wordpress shortcode, giving me an array of ids to build a list of links. Everything's fine so far. But now I'd like to number these links, so I use $key to output the index. Unfortunately numbering (within the span tag) starts with zero (0) and I can't figure a way to add + 1 to $key :(
function wp_ytlinks($atts){
extract(shortcode_atts(array( 'id' => 1 ), $atts));
echo '<div class="videonav">';
$value = explode(',', $id);
$index = 0;
foreach ($value as $key=>$att_id)
{
echo '<a class="yt-vid" id="yt-load" href="http://www.youtube.com/embed/' .
$att_id . '?rel=0" target="screen"><span>' . $key . '</span></a>';
}
};
add_shortcode('ytlinks', 'wp_ytlinks');
The Shortcode looks like this: [ytlinks id="J0Np2hn84Tc,cVHGLdZQgEw"]
Can s.o. please help?
OKay, I don't know, after an hour of stupid back and forth I tried something REALLY easy and it worked...
foreach ($value as $key=>$att_id) {
$nums = $key + 1;
...
Why do I have to post a question here to find such an easy solution?! Sorry guys...

How to skip the first instance in a foreach loop and limit to 8?

I was wondering if anyone could give me a hand with this...
Basically I am trying to modernize the news system of my site but I can't seem to limit the amount of posts showing in the foreach loop that is on my blog part of the site. I need to skip the first instance as it is already promoted at the top of the page. I've tried various google searches but im getting results for C++ Perl and python, what is really irritating. I just need a simple PHP solution. I'll pop my code below and see if anyone can help. Thanks for any help in-advance. And please remember to leave your responses as an answer so I can mark them up if they helped ;)
<div class="view22 full" style="margin-top:0;">
<h3>Recent News and Announcements</h3>
<?php foreach ($articles as $article) {
?>
<div class="ah7_ clearfix">
<p class="date"><?php echo date('F j', $article['article_timestamp']); ?>, <?php echo date('Y', $article['article_timestamp']); ?></p>
<h3><?php echo $article['article_title']; ?></h3>
</div>
<?php
}
?>
</div>
I assume that the $articles array has keys starting with 0. How about modifying the loop like this:
foreach ($articles as $key => $article)
and checking if $key is 0 at the beginning?
if($key == 0)
continue;
If the array keys are different: Create a new variable $i, set it to 0 and increase the value by 1 in every foreach loop iteration.
$i = 0;
foreach ($articles as $article) {
$i++;
if($i == 1)
continue;
elseif($i > 8)
break;
//the other code goes here
}
In case it is based on a SQL query, using "limit" might help to reduce load!
There are a few things you can do:
If you $articles is an array of array, having continous indexes, use a for loop instead of foreach and do something like
for ($i = 1; $i < 8 : $i++ ) {
// and access it like
$articles[$i]['some_index'] ...
}
If it is not then you can use an external counter
Say
$counter = -1;
foreach ( $articles as $article) {
$counter++;
if (!$counter) continue;
if ($counter > 7 ) break;
...// your code //
}
You can change your Mysql query to give you only the desired data, using LIMIT and OFFSET
To remove the first instance you can manually unset the item ($articles[0]) after making a copy of it or printing it as a featured news.
To limit the number of post you can use the mysql LIMIT Clause;
Or you can do something like this
foreach($articles as $key => $article){
if($key===0)
continue;
if($key===8)
break;
echo $article;// or_do_whatever_youwant_with($article);
}

PHP nested loop behaving unexpectedly

I have an array which contains the categories for a particular article ($link_cat). I'm then using mysql_fetch_array to print out all of the categories available into a list with checkboxes. While it's doing this I want it to compare the value it's on, to a value from the other array. If there is a match, then it means that one of the categories applies to this article, and it should print out a line of code to apply the checked attribute. great! except it's not working =[
while ( $row = mysqli_fetch_array($results, MYSQLI_ASSOC) ){
$cat[$i] = $row['category'];
$cat_id[$i] = $row['cat_id'];
echo '<li><input type="checkbox" ';
$catCount = count($link_cat);
for ($ct = 0; $ct < $catCount; $ct++){
if ($cat_id[$i] == $link_cat[$ct]){
echo 'checked="checked" ';
}
}
echo 'name="' . $cat_id[$i] . '" />' . $cat[$i] . '</li>';
$i++;
}
I've never really done a nested loop before (I suspect thats the problem).
The problem seems to be that when this runs, $link_cat[0] which will have the first category to check against in it - doesn't register. It comes up blank. Printing out variables inside the for loop confirmed this. Any others [1] [2] etc, are fine. It's just [0]. But why? it doesn't seem to make any sense. I know there is something in there, because I printed the contents of array as I filled it it, just to check. Yet it doesn't just show during the loop. Any ideas?
slight bug fix (and blatant style change): Your version can print out checked="checked" multiple times. Do $cat and $cat_id need to be arrays?
while ( $row = mysqli_fetch_array($results, MYSQLI_ASSOC) ) {
$cat = $row['category'];
$cat_id = $row['cat_id'];
echo '<li><input type="checkbox" ';
if ( in_array($cat_id, $link_cat) ) {
echo 'checked="checked" ';
}
echo "name='$cat_id' />$cat</li>";
}
For situation where one would normally throw a debugger at a problem, I like to throw in a nice print_r in a comment block (view-source for debug output, safer on live-ish sites).
echo '<!-- ' . print_r($link_cat, TRUE) . ' -->';
While I was originally very wrong about the array looping needing a reset, I can't shake the feeling that looping through that array isn't the fastest way to do what you are after.
Perhaps array_search would do, or maybe array_key_exists. in_array look like a winner but I didn't think of it

dynamic rows and columns inside a foreach loop

I'm trying, but I'm stucked with the logic... so, I have this:
$max_items=10;
echo '<table>';
echo '<tr>';
foreach ($feed->get_items(0, $max_items) as $item):
echo '<td>';
echo $some_value;
echo '</td>';
endforeach;
echo '</tr>';
echo '</table>';
I want to show the results like this:
[1][2]
[3][4]
[5][6]
[7][8]
[9][10]
I have to use a while statement? A for loop? Inside or outside the foreach code?
I really don't get it...
Thanks for any kind of help
Here's a very simple example of how to do this sort of HTML building.
<?php
$data = range( 'a', 'z' );
$numCols = 2;
echo "<table>\n";
echo "\t<tr>\n";
foreach( $data as $i => $item )
{
if ( $i != 0 && $i++ % $numCols == 0 )
{
echo "\t</tr>\n\t<tr>\n";
}
echo "\t\t<td>$item</td>\n";
}
echo "\t</tr>\n";
echo '</table>';
This way, you can change $numCols to be 3 or 4 (or any number) and always see that number of columns in the output, and it does so without using an nested loop.
Take a look at this link to Displaying Recent Posts On a Non-WordPress Page. I think what you may be looking for is a way to loop over the objects get methods. For that you will need a nested loop and some sort of reflection.
I was just recently working with SimplePie on the February release of Cogenuity so this is still fresh in my mind.
Your $some_value variable never gets initialized.
The $item object will have such methods as get_permalink(), get_title(), get_description(), and get_date()

Categories