Pluck structured data?

Hello,

I’m trying to display all clients testimonials on my home page. Testimonials are by projects, so they are in each individual project page under the form of a structured field (quote, name of the client, role, client picture).

So I tried this:

<?php foreach(page('projects')->children()->pluck('clientTestimonials')->toStructure()->limit(2) as $testimonial): ?>

and have the error “Fatal error: Call to a member function children() on boolean in /templates/home.php on line 274”

Then I tried this:

<?php foreach(page('projects')->children->clientTestimonials()->toStructure()->limit(2) as $testimonial): ?>

with non luck either

Same error message as above + “Notice: Trying to get property of non-object in /templates/home.php on line 274”

Does a structured field can be plucked ? How can I do what i want to do ? With 2 foreach ?

Thanks

You can’t use pluck(). Check out this post for a solution.

thank you.

I tried this:

<?php
$projects = page('project')->children()->visible();
	$testimonials = new Structure();
	foreach($projects as $p) {
	$testimonials = $testimonials->merge($p);
	}
	foreach($testimonials as $testimonial):
?>

with no success and this error message:

Notice: Undefined property: Page::$data in /kirby/toolkit/lib/collection.php on line 40
Warning: Invalid argument supplied for foreach() in /kirby/toolkit/lib/a.php on line 463

Use the example (see below) before with the $key, that last one does not work.

<?php
$subaktuelles = $site->index()->findBy("uid", "aktuell")->children()->visible();
$neuigkeiten = new Structure();
$key = 0;
foreach($subaktuelles as $p) {
  foreach($p->news()->toStructure() as $item) {
    $neuigkeiten->append($key, $item);
    $key++;
  }
}

foreach ($neuigkeiten->sortBy('date', 'desc') as $neuigkeit): ?>

Ok I tried it, it kinda works.

first problem:
<?php foreach ($testimonials as $testimonial): ?> gives me all the testimonials “plucked” and it seems that i can’t chain ->shuffle() or ->limit(3) to it (in your example you can sort it and chain easily). Is this normal ?

Second problem:
<?php echo $testimonial->clientTestimonial()->kt() ?> echoes the clientTestimonial field (great) but all the others fields echo the same thing, for example <?php echo $testimonial->clientTestimonialName() ?> also echoes clientTestimonial instead of the right field and I can’t find why.

any ideas ?

//Edit : in fact the first testimonial is empty, the second is just the quote repeated, the third is just the name, the fourth is just the role etc… I’m going to investigate.

//Edit 2: in fact it’s repeating only one of the items over and over.

Could you pls. post your new code?

Sure:

<?php
$projects = page('projets')->children()->visible();
$testimonials = new Structure();
$key = 0;
foreach($projects as $p) {
  foreach($p->clientTestimonials()->toStructure() as $item) {
    $testimonials->append($key, $item);
    $key++;
  }
}
foreach ($testimonials as $testimonial): ?>
<!--some html ul li for repeated item-->
<blockquote>
<?php echo $testimonial->clientTestimonial()->kt() ?>
</blockquote>
<p><strong><?php echo $testimonial->clientTestimonialName() ?></strong><span><?php echo $testimonial->clientTestimonialRole() ?></span></p>
 <!--end of html block-->
<?php endforeach ?>

and the datas:

----

clientTestimonials:

-
    clientTestimonial: Vestibulum quam nisi, pretium a nibh sit amet, consectetur hendrerit mi. Aenean imperdiet lacus sit amet elit porta, et malesuada erat bibendum.
    clientTestimonialName: Jean Dupont-avec-un-nom-très-long
    clientTestimonialRole: Gestionnaire de syndic
    clientTestimonialAvatar: rien
-
    clientTestimonial: Vestibulum quam nisi, pretium a nibh sit amet, consectetur hendrerit mi.
    clientTestimonialName: Miriam Jonhson
    clientTestimonialRole: Gardienne
    clientTestimonialAvatar: rien
-
    clientTestimonial: Aenean imperdiet lacus sit amet elit porta, et malesuada erat bibendum.
    clientTestimonialName: Robert Di Caprio
    clientTestimonialRole: Chef de chantier
    clientTestimonialAvatar: rien
    
----

Hm, I’m very sorry, I can’t spot anything wrong here; I have the same sort of structure in one of my projects and use the same code without any problems …

Very strange, it’s like the foreach is on the wrond code, I will look it further but I’m neraly stuck on that.

Thanks for your help.

OK, i don’t know why as I just copied the code from above, but this time it works!

<?php
$projects = page('projets')->children()->visible();
$testimonials = new Structure();
$key = 0;
foreach($projects as $p) {
  foreach($p->clientTestimonials()->toStructure() as $item) {
    $testimonials->append($key, $item);
    $key++;
  }
}
foreach ($testimonials->limit(3) as $testimonial): ?>									
<!--some html markup-->
<?php echo $testimonial->clientTestimonial()->kt() ?>
<?php echo $testimonial->clientTestimonialName() ?>
<?php echo $testimonial->clientTestimonialRole() ?>
<!--end of html markup-->
<?php endforeach ?>

As it’s the same code, maybe my data were corrupted or the data syntax not right on one page.

Last question though: I can’t shuffle() anything anywhere, dont know why it doesn’t work altough limit() works fine now.

The error when I try to do foreach ($testimonials->shuffle()->limit(3) as $testimonial) :

Fatal error: Call to a member function clientTestimonial() on integer in /site/templates/home.php on line 288

When I try to shuffle on others collections, it does not drop error but it doesn’t shuffle anything

Thank you @texnixe for your help!

Yes, that’s a known issue; the structure collection has some limitations compared to other collections.

Glad you sorted it out.

Ok, any idea on how I can shuffle it with vanilla php ? And why when I shuffle on the first collection page('projets')->children()->visible()->shuffle I always end with the same result ?

I think, currently the only way to achieve that would be to use the yaml() method instead of toStructure() and then shuffle the array.

I encountered that problem back in August last year, but it hasn’t been fixed since.

I had this idea too but I didn’t know how to implement it. Where can I put the yaml ?

Also I don’t understand why when I shuffle the first pages collection it doesn’t change anything, at least the testimonials had to be shuffled by page.

The content would be unchanged, but instead of using toStructure in your template you would use yaml. It returns a plain PHP array that can be manipulated with the standard PHP functions.
You would also use a plain array for $testimonials instead of a new Structure(). You can add items to an array with $testimonials[] = $item.

some follow up, a friend of mine helps me for achieving this, and I post the code here if it can help somebody else.

My first code, works but no random:

<?php
                $projects = page('projets')->children()->visible();
                $testimonials = new Structure();
                $key = 0;
                foreach($projects as $p) {
                  foreach($p->clientTestimonials()->toStructure() as $item) {
                    $testimonials->append($key, $item);
                    $key++;
                }
            }
            foreach ($testimonials->limit(5) as $testimonial): ?>									
            <li class="item">
               <div class="testimonial-block">
                <blockquote>
                    <?php echo $testimonial->clientTestimonial()->kt() ?>
                </blockquote>
                <div class="testimonial-avatar"><img src="http://placehold.it/100x100&amp;text=IMAGE+PLACEHOLDER" alt="" height="60" width="60"></div>
                <div class="testimonial-info">
                    <div class="testimonial-info-in">
                        <strong><?php echo $testimonial->clientTestimonialName() ?></strong><span><?php echo $testimonial->clientTestimonialRole() ?></span>
                    </div>
                </div>
            </div>
        </li>
    <?php endforeach ?> 

the code with “all array” in vanilla PHP + randomisation and limit to 5 items:

<?php
$projects = page('projets')->children()->visible();
$testimonials = array();
foreach($projects as $p) {
  foreach($p->clientTestimonials()->yaml() as $item) {
    $testimonials[] = $item;
  }
}
shuffle($testimonials);
$testimonialscount = count($testimonials);
$i = 0;
while($i < 5) { ?>
	<li class="item">
               <div class="testimonial-block">
                <blockquote>
                    <?php echo $testimonials[$i]["clientTestimonial"]; ?>
                </blockquote>
                <div class="testimonial-avatar"><img src="http://placehold.it/100x100&amp;text=IMAGE+PLACEHOLDER" alt="" height="60" width="60"></div>
                <div class="testimonial-info">
                    <div class="testimonial-info-in">
                        <strong><?php echo $testimonials[$i]["clientTestimonialName"]; ?></strong><span><?php echo $testimonials[$i]["clientTestimonialRole"]; ?></span>
                    </div>
                </div>
            </div>
        </li>
<?php	$i++;
if($i >= $testimonialscount): break; endif;
}
?>

Thanks everybody!

Thanks for sharing your solution :slight_smile:

you’re welcome.

I edited my code with a solution to avoid the offset limit problem (if you set 5 items but the array have only 3 of them for example)

Shuffling structure collections will finally work in Kirby 2.3.1. :slight_smile:

1 Like

Cool ! Thank you, I will update and rewrite this correctly.