Foreach loop within foreach loop is echoing the array - php

I am using the cms perch to retrieve data using various functions. I am retrieving product items from various sub pages. The code I have so far is working as it should and can be seen here: http://www.ww.thirdfloordesign.net/products/70mm-couplers/
$raw = perch_pages_navigation(array(
'from-path'=>'*',
'skip-template'=>true
));
if (count($raw)) {
$items = $raw;
} else {
// add else statement to output warning 'no products found in this category' or something
}
foreach($items as $item) {
$product['ID'] = $item['pageNavText'];
$product['title'] = $item['pageTitle'];
$product['path'] = $item['pagePath'];
$product['parent'] = $item['pageSubpagePath'];
PerchSystem::set_vars(array(
'product-id'=>$product['ID'],
'product-title'=>$product['title'],
'product-path'=>$product['path'],
'product-parent'=>$product['parent']
));
$product['image'] = perch_content_custom('Image', array(
'page'=>$product['path'],
'template'=>'product/_image.html',
'sort'=>'_order',
'count'=>1
), true);
PerchSystem::set_var('product-image', $product['image']);
$items[] = perch_content_custom('Product', array(
'page'=>$product['path'],
'template'=>'product/_product.html'
), true);
}
Where the data needs to be outputted I am using the following code and it seems to be working as it should except it is also echoing an array which can be seen on the page. Is it because I am using duplicate $variables / array names? Solutions please
<?php
if (!empty($items)) {
?>
<ul class="product-grid">
<?php
foreach($items as $item) {
echo $item;
}
?>
</ul>
<?php
} else {
?>
<p class="alert alert-warning"><i class="icon-warning-sign"></i>No products found!</p>
<?php } ?>

Related

PHP - creating a new array through nested arrays while creating a post/image relationship

PHP 7.2
Wordpress 4.9.8
Advanced Custom Fields 5.7.7
I'm interested in creating an array where each item would hold:
post id
post title
array of images belonging to post
I am using an ACF repeater for every post that holds many images, the repeater name is carousel.
There is no connection between the WP post object and the ACF fields.
The issue:
nested foreach pushes all the images into the first post.
Expected:
nested foreach will fill the $randomArray only with images that belong to that post ID.
$workshop_posts_args = array(
'post_type' => 'workshops'
);
$randomArray = [
'post_id' => '',
'post_title' => '',
'post_image_url' => []
];
$post_query = new WP_Query($workshop_posts_args);
if ($post_query->have_posts()) {
while ($post_query->have_posts()) {
$post_query->the_post();
$carousel_array = get_field('carousel', get_the_ID());
echo "<h2>".get_the_title()."</h2>";
if ($carousel_array) {
foreach ($carousel_array as $carousel_images) {
foreach ($carousel_images as $image) {
$randomArray['post_id'] = get_the_ID();
$randomArray['post_title'] = get_the_title();
$randomArray['post_image_url'][] = $image['url'];
echo 'image_url:'.$image['url'].'<br>The array: <pre>'.print_r($randomArray, true).'</pre>';
?>
<?php
}
}
}
}
}
?>
<h1>TOTAL ARRAY</h1>
<pre><?php print_r($randomArray) ?></pre>
You are over-writing array index again and again inside loop and that's you problem.
so do:-
$randomArray = []; //before post_query
And change if block like below:-
if ($post_query->have_posts()) {
while ($post_query->have_posts()) {
$post_query->the_post();
$id = get_the_ID();
$randomArray[$id]['post_id'] = $id;
$randomArray[$id]['post_title'] = get_the_title();
$carousel_array = get_field('carousel', $id);
if ($carousel_array) {
foreach ($carousel_array as $carousel_images) {
foreach ($carousel_images as $image) {
$randomArray[$id]['post_image_url'][] = $image['url'];
?>
<?php
}
}
}
}
}
Note:- rest code will be same
the above code will give you post-id based multi-dimensional array. if you want indexes to be 0,1,2,3..... format then do:-
$randomArray = array_values($randomArray);
Use proper indexing of $randomArray like below:
<?php
$workshop_posts_args = array(
'post_type' => 'workshops'
);
$randomArray = array();
$post_query = new WP_Query($workshop_posts_args);
$index = 0;
if ($post_query->have_posts()) {
while ($post_query->have_posts()) {
$post_query->the_post();
$randomArray[$index]['post_id'] = get_the_ID();
$randomArray[$index]['post_title'] = get_the_title();
$carousel_array = get_field('carousel', get_the_ID());
//echo "<h2>".get_the_title()."</h2>";
if ($carousel_array) {
foreach ($carousel_array as $carousel_images) {
foreach ($carousel_images as $image) {
$randomArray[$index]['post_image_url'][] = $image['url'];
//echo 'image_url:'.$image['url'].'<br>The array: <pre>'.print_r($randomArray, true).'</pre>';
?>
<?php
}
}
}
$index++;
}
}
?>
<h1>TOTAL ARRAY</h1>
<pre><?php print_r($randomArray) ?></pre>

PHP: Best practice with repeating lines of code without a clear input/output (DRY)

I have an HMVC webapplication developed in PHP.
In my controller and in my view, I need to iterate over multiple arrays. Between the iterations I need to use/echo some values out of the array. The problem is that my code is a mess and I was wondering if there are better best practices to do this kind of loops.
For the following examples: $header has 15 values and $groups has 1000 values.
I have the following (simplified) example of code in my view:
<? foreach($headers as $header) { ?>
<div class="header"><?= $header->number ?></div>
<? $i = 0; ?>
<? foreach($groups as $group) { ?>
<? $part_letter = $group->part->letter ?>
<? if ($group->number !== $header->number) { continue; } ?>
<? $i++; ?>
<? if ($i === 1) { $first_group = true; } else { $first_group = false; } ?>
<div class="<?= $first_group ? 'colored' : ''>
<?= echo $group->name ?>
<?= echo $part_letter ?>
</div>
<? } ?>
<? } ?>
I have the following (simplified) example of code in my controller:
foreach($headers as $header) {
$pdf[] = $header->number;
$i = 0;
foreach($groups as $group) {
$part_letter = $group->part->letter;
if ($group->number !== $header->number) { continue; }
$i++;
if ($i === 1) { $first_group = true; } else { $first_group = false; }
$pdf['first_group'] = $first_group;
$pdf['group_name'] = $group->name;
$pdf['part_letter'] = $part_letter;
}
}
My thoughts
My first thought was, since the iteration in the controller and view are the same, to move this to a separate function where input would be $headers and $groups, but what would be the output? In the view I need some array values between HTML code and in the controller I need to save them in the $pdf array.
My second thought was to create a separate function to iterate over both arrays to create a 3rd and 4th array with all significant values in it. That 3rd and 4th array would look something like this:
$header_values[$id] = $number;
$group_values[$id] = array($part_letter, $group_equals_header_number, $is_first_group);
Then my controller would look like this:
foreach($header_values as $header_value) {
$pdf[] = $header_value;
foreach($group_values as $group_value) {
if (!$group_value['group_equals_header_number']) { continue; }
$pdf['first_group'] = $group_value['is_first_group'];
$pdf['group_name'] = $group_value['group_name'];
$pdf['part_letter'] = $group_value['part_letter'];
}
}
And my view would look like this:
<? if (!$group_value['group_equals_header_number']) { continue; } ?>
<div class="<?= $group_value['is_first_group'] ? 'colored' : ''>
<?= echo $group_value['group_name'] ?>
<?= echo $group_value['part_letter'] ?>
</div>
It looks a bit better, the downside is that I need an extra iteration.
What is best practice with this kind of repeating loops / repeating code, while keeping my code DRY?
sorry for my too quick comment, i don't have seen that the "group loop" is not a children of $header then in this case, you can waste time if you have lots of headers and lots of groups in differents headers
you can try this code, it will use a little more time for the first task but it will spare more time for the second task
<?php
////////////////////////////////////////////////////
// *** first task : grouping "groups" by header
$listHeaders = [];
// searching all the headers numbers
foreach ($headers as $header)) {
$listHeaders[$header->number] = $header;
}
// associating groups with header
foreach ($groups as $group) {
$headerNumber = $group->number;
if (!isset($listHeaders[$headerNumber])) {
continue;
}
if (!isset($listHeaders[$headerNumber]->listGroups)) {
$listHeaders[$headerNumber]->listGroups = [];
}
$listHeaders[$headerNumber]->listGroups[] = $group;
}
////////////////////////////////////////////////////
// *** second task : display
foreach ($listHeaders as $headerNumber => $header) {
?>
<div class="header">
<?php echo $headerNumber;?>
</div>
<?php
foreach ($header->listGroups as $index => $group) {
?>
<div class="<?php echo (0 !== $index) ? "" : "colored";?>">
<?php echo $group->name;?>
<?php echo $group->part->letter;?>
</div>
<?php
} // END foreach ($header->listGroups as $index => $group) {
} // END foreach ($listHeaders as $headerNumber => $header) {
just do benchmarks to choose wich code take less time with your datas

Outputting categories authors have written in as a class (WordPress)

OK, I have a very specific question that I hope someone can shed some light on.
I have a page that lists authors outputting using the following code
<?php
$display_admins = false;
$order_by = 'post_count'; // 'nicename', 'email', 'url', 'registered', 'display_name', or 'post_count'
$role = ''; // 'subscriber', 'contributor', 'editor', 'author' - leave blank for 'all'
$hide_empty = true; // hides authors with zero posts
if(!empty($display_admins)) {
$blogusers = get_users('orderby='.$order_by.'&role='.$role);
} else {
$admins = get_users('role=administrator');
$exclude = array();
foreach($admins as $ad) {
$exclude[] = $ad->ID;
}
$exclude = implode(',', $exclude);
$blogusers = get_users('exclude='.$exclude.'&orderby='.$order_by.'&role='.$role.'&order='.'DESC');
}
$authors = array();
foreach ($blogusers as $bloguser) {
$user = get_userdata($bloguser->ID);
if(!empty($hide_empty)) {
$numposts = count_user_posts($user->ID);
if($numposts < 1) continue;
}
$authors[] = (array) $user;
}
echo '<ul class="contributors">';
foreach($authors as $author) {
$display_name = $author['data']->display_name;
$avatar = get_wp_user_avatar($author['ID'], 'medium');
$author_profile_url = get_author_posts_url($author['ID']);
$filter = get_userdata($author['ID'])->yim;
echo '<li><div class="home ', $filter,' "><div class="feature-image">', $avatar , '</div>
<div class="post-title"><h3>', $display_name, '</h3></div>
</div>
</li>';
}
echo '</ul>';
?>
(I got this from another support topic and tweaked it, although I can't remember where)
At the moment, the $filter variable is just a string I enter in the 'Yahoo IM' profile box (a dirty fix to test the filter). I'd like this to actually be a list of the categories (as slugs that I will output in to the class="" part of the loop) that the author has posted in.
I essentially want to be able to filter the authors by category that they have posted in, and the filter I'm using (Isotope) operates using the class, so outputting the categories in to the class of the markup is what I'm after.
Any suggestions gratefully received!
// Returns the posts made by the author
$authorPosts = get_posts("author={$author['ID']}");
$categoryList = array(); // reset previous values
foreach ($authorPosts as $post) {
$postCategories = get_the_category($post->ID);
// Add to the categories the author has posted in
foreach ($postCategories as $category)
$categoryList[] = $category->slug;
}
// Removes duplicate categories
$categoryList = array_unique($categoryList);
You can then use $filter = implode(' ', $categoryList); and add it to your html.
RE not storing the array from the other answer, you can just echo out the slugs there and then like this:
$authorPosts = get_posts("author={$author['ID']}");
foreach ($authorPosts as $post) {
$postCategories = get_the_category($post->ID);
// Add to the categories the author has posted in
foreach ($postCategories as $category)
echo($category->slug);
}
otherwise if you want to put your PHP at the top and echo out the slugs further down the page pop there where ever you want to echo them:
$i = 0;
foreach($categoryList as $category) {
echo($categoryList[$i]);
$i++;
}

Organizing results by category Redux

I am trying to expand on my question asked here: Creating a multi-dimensional array from query
I have added a category description to my categories table but I cannot figure out how to add it to the code below and display each category description for each category.
Here is the code I am using to display the items by category:
$itemcategories = array();
while ($row = mysqli_fetch_array($result))
{
$head = $row['category'];
$itemcategories[$head][] = array(
'id' => $row['id'],
'title' => $row['title'],
'itemdesc' => $row['itemdesc'],
'price' => $row['price'],
'special' => $row['special']
);
}
<?php foreach ($itemcategories as $head => $items) { ?>
<h3><?php echo $head; ?></h3>
<table class="chart">
<?php foreach ($items as $item) { ?>
<tr><td><?php echo $item['itemdesc']; ?></td></tr>
<?php } ?>
</table>
<?php } ?>
// to initial variable holder
$categories = $items = array();
// looping mysql result
while ($row = mysqli_fetch_array($result))
{
// to get category name
$head = $row['category'];
// avoid excessive setting of $categories
if (!isset($categories[$head]))
{
$categories[$head] = $row['descrption'];
}
// assign mysql result to $items
$items[$head][] = $row;
}
// free mysql result
mysql_free_result($result);
// loop all $categories
foreach ($categories as $head=>$desc)
{
// this is my example for printing HTML
// you can use heredoc syntax
// or stick to your existing format
echo "<h3>{$head} - {$desc}</h3><table class="chart">";
foreach ($items[$head] as $item)
{
// print item description
echo "<tr><td>{$item['itemdesc']}</td></tr>";
}
echo "</table>";
}

Wordpress rewind query not working

I've got a little sidebar that displaying in the code before the main page content. I wrote this (janky) function to pull in recent posts and comments. Works great, however, its screwing with all my pages and putting posts on all of them. How do I reset/rewind the query or make a new one so all my pages display the correct content?
<?php rewind_posts(); ?>and<?php wp_reset_query(); ?> arent doing the trick for me
Here is my query:
$comments = get_comments('number=10');
$posts = get_posts('posts_per_page=10&category=6');
$most_recent = array();
foreach ($comments as $comment)
$most_recent[strtotime($comment->comment_date_gmt)] = $comment;
foreach ($posts as $post)
$most_recent[strtotime($post->post_date_gmt)] = $post;
unset($comments, $posts);
krsort($most_recent);
$most_recent = array_slice($most_recent, 0, 10);
foreach ($most_recent as $post_or_comment) {
$is_post = isset($post_or_comment->post_date_gmt);
$comment_id = $post_or_comment->comment_ID;
$post_id = $post_or_comment->ID;
$comment_post_id = $post_or_comment->comment_post_ID;
if ($is_post == 1)
{ ?> <li><?php echo $post_or_comment->post_title; ?><span class="tag"><?php echo the_category($post_id); ?></span></li><?php }
else
{ ?><li> <?php echo get_the_title($comment_post_id); ?><span class="tag">Comment</span></li><?php }
// output comments and posts
}
output comments and posts
}
Try using $my_posts and $my_comments instead, just in case WP is using samely-named globals (though I don't think it is).
Also, in your foreach loop, you should only be casting variables when you know the object type, otherwise you're accessing non-existent properties;
foreach ($most_recent as $post_or_comment) {
$is_post = isset($post_or_comment->post_date_gmt);
if ($is_post) {
$post_id = $post_or_comment->ID;
} else {
$comment_id = $post_or_comment->comment_ID;
$comment_post_id = $post_or_comment->comment_post_ID;
}
}
rewind_posts() will have no effect here. Just call wp_reset_query() right after the foreach loop ends.

Categories