Jump to content

Splitting PageArray into two new arrays (with half the items each)


SamC
 Share

Recommended Posts

I'm building a testimonials page, and currently have this (one review will always be at the top, the first one, whichever that may be after shuffling):

// views/testimonials.php
<?php namespace ProcessWire; ?>

<?php
    $arr = $page->testimonials;
    $arr->shuffle();
    $firstTestimonial = $arr->first();
    $otherTestimonials = $arr->not("$firstTestimonial");
?>

<div class="jumbotron jumbotron-fluid bg-color">
    <div class="container">
        <h2><?= $firstTestimonial->title; ?></h2>
        <p><?= $firstTestimonial->testimonialBody; ?> - <i><?= $firstTestimonial->testimonialReviewee; ?></i></p>
    </div>
</div>

<div class='container'>
    <div class='row py-6'>

    <?php foreach($otherTestimonials as $testimonial): ?>
    
        <div class='col-sm-12 col-md-6 py-3 px-lg-5'>
            <h2 class='py-3'><?= $testimonial->title; ?></h2>
            <p><?= $testimonial->testimonialBody; ?></p>
            <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p>
        </div>

    <?php endforeach; ?>

    </div>
</div>

... the problem I have is from a design perspective. Using a flexbox grid means columns are equal height. Each row contains three columns on desktop. Now, if one column has shorter content than the next one, there is large white space under it because it doesn't fill the column vertically (but the longer ones do). You end up with this:

------------------------------------------------------------------------------
Title                       Title                       Title
ngjkagas ndjskagdasj        njgksgnjsk gdjkgasjk        gdjskgbjksa gdasjgkads
gndjaskgnjdasnjg ds         gbdjskgbdjkab dgasnjk       jgfksjgfds jgdksajkgds
njdkajda njdasxlhs gf                                   jkdgjsagjdajdasdga
fdjakfdbjak fhdjkahf                                    fdbjabfdj fdjsjkakjka
------------------------------------------------------------------------------
Title                       Title                       Title
ngjkagas ndjskagdasj        njgksgnjsk gdjkgasjk        gdjskgbjksa gdasjgkads
gndjaskgnjdasnjg ds         gbdjskgbdjkab dgasnjk       jgfksjgfds jgdksajkgds
njdkajda njdasxlhs gf                                   jkdgjsagjdajdasdga
fdjakfdbjak fhdjkahf                                    fdbjabfdj fdjsjkakjka
fnfsjsjs dhhdsjsjds                                     fdnsjkfdjs fdhj dhksd
------------------------------------------------------------------------------

So I thought I'd get the original PageArray, split it into two equal parts, then just loop the two new arrays into two columns. to get this:
 

--------------------------------    --------------------------------
Title                               Title
ngjkagas ndjskagdasj                gdjskgbjksa gdasjgkads
gndjaskgnjdasnjg ds                 gbdjskgbdjkab dgasnjk
njdkajda njdasxlhs gf               jgfksjgfds jgdksajkgds
jkdgjsagjdajdasdga
fdjakfdbjak fhdjkahf                Title                  
fdbjabfdj fdjsjkakjka               jfdksahfjka hfdjkasfhjdafalk
fnfsjsjs dhhdsjsjds                 ndjskagjka hdsk hjkdsahjkgd
fdnsjkfdjs fdhj dhksd               jgdskgksa hgdjskahgjdashgkdas

Title                               Title
ngjkagas ndjskagdasj                gdjskgbjksa gdasjgkads
gndjaskgnjdasnjg ds                 gbdjskgbdjkab dgasnjk
njdkajda njdasxlhs gf               jgfksjgfds jgdksajkgds
jkdgjsagjdajdasdga
fdjakfdbjak fhdjkahf                Title                  
fdbjabfdj fdjsjkakjka               jfdksahfjka hfdjkasfhjdafalk
fnfsjsjs dhhdsjsjds                 ndjskagjka hdsk hjkdsahjkgd
fdnsjkfdjs fdhj dhksd               jgdskgksa hgdjskahgjdashgkdas
--------------------------------    --------------------------------

So my new code is sketchy and I could do with some help to possibly refactor and also to fill in the gaps where my knowledge fails. Here it is so far:

<?php namespace ProcessWire; ?>

<?php
    // get PageArray of all testimonials (which is a repeater: title, testimonialReviewee, testimonialReviewee)
    $arr = $page->testimonials;
    // shuffle them
    $arr->shuffle();
    // grab the first one
    $firstTestimonial = $arr->first();
    // grab the others
    $otherTestimonials = $arr->not("$firstTestimonial");
    // get total items in array
    $numberOfItems = count($otherTestimonials);
    // return new PageArray (half of $otherTestimonials)
    $firstHalfArr = $otherTestimonials->slice(0, ($numberOfItems / 2));
    // return new PageArray (half + 1) to end
    $secondHalfArr = $otherTestimonials->slice(($numberOfItems / 2) + 1, $numberOfItems);
?>

<div class="jumbotron jumbotron-fluid bg-color">
    <div class="container">
        <h2><?= $firstTestimonial->title; ?></h2>
        <p><?= $firstTestimonial->testimonialBody; ?> - <i><?= $firstTestimonial->testimonialReviewee; ?></i></p>
    </div>
</div>

<div class='container'>
    <div class='row'>
        <div class='col-6'>
        
        <?php foreach($firstHalfArr as $testimonial): ?>
    
            <h2 class='py-3'><?= $testimonial->title; ?></h2>
            <p><?= $testimonial->testimonialBody; ?></p>
            <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p>

        <?php endforeach; ?>

        </div>

        <div class='col-6'>
        
        <?php foreach($secondHalfArr as $testimonial): ?>
    
            <h2 class='py-3'><?= $testimonial->title; ?></h2>
            <p><?= $testimonial->testimonialBody; ?></p>
            <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p>

        <?php endforeach; ?>

        </div>
    </div>
</div>

Sure you guys don't need the comments but it helps me as I go along to build the logic.

The obvious problem is what happens when the PageArray contains an odd number of items. Is there a round method or something? If I round incorrectly though, I think maybe one testimonial item would be missed i.e. [0,1,2,3] and [5,6,7,8].

Anyway, the problem I'm having right now in PHP and JS as I learn is thinking like a programmer. I'm getting better at reading technical docs and using methods from instructions etc. but the thinking like a programmer bit (logic included) eludes me somewhat. I'll get there in the end. Any advice is appreciated as always. Thanks.

(p.s. I am aware of CSS3 column-count)

  • Like 1
Link to comment
Share on other sites

Actually, this seems to work:

<?php namespace ProcessWire; ?>

<?php
    // get PageArray of all testimonials (which is a repeater: title, testimonialReviewee, testimonialReviewee)
    $arr = $page->testimonials;
    // shuffle them
    $arr->shuffle();
    // grab the first one
    $firstTestimonial = $arr->first();
    // grab the others
    $otherTestimonials = $arr->not("$firstTestimonial");
    // get total of half the array
    $numberInFirstHalf = ceil(count($otherTestimonials) / 2);
    // return new PageArray (half of $otherTestimonials)
    $firstHalfArr = $otherTestimonials->slice(0, $numberInFirstHalf);
    // return new PageArray (halfway to end)
    $secondHalfArr = $otherTestimonials->slice($numberInFirstHalf, $numberOfItems);
?>

<div class="jumbotron jumbotron-fluid bg-color">
    <div class="container">
        <h2><?= $firstTestimonial->title; ?></h2>
        <p><?= $firstTestimonial->testimonialBody; ?> - <i><?= $firstTestimonial->testimonialReviewee; ?></i></p>
    </div>
</div>

<div class='container'>
    <div class='row'>
        <div class='col-6'>
        
        <?php foreach($firstHalfArr as $testimonial): ?>
    
            <h2 class='py-3'><?= $testimonial->title; ?></h2>
            <p><?= $testimonial->testimonialBody; ?></p>
            <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p>

        <?php endforeach; ?>

        </div>

        <div class='col-6'>
        
        <?php foreach($secondHalfArr as $testimonial): ?>
    
            <h2 class='py-3'><?= $testimonial->title; ?></h2>
            <p><?= $testimonial->testimonialBody; ?></p>
            <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p>

        <?php endforeach; ?>

        </div>
    </div>
</div>

I get one main one featured at top, 3 in left column and 2 in right column, total of 6 testimonials.

  • Like 1
Link to comment
Share on other sites

Nice one. :)

Just another way to skin the cat...

<?php
$testimonials = $page->testimonials;
$testimonials->shuffle();
$firstTestimonial = $testimonials->shift();
?>

<div class="jumbotron jumbotron-fluid bg-color">
    <div class="container">
        <h2><?= $firstTestimonial->title; ?></h2>
        <p><?= $firstTestimonial->testimonialBody; ?> - <i><?= $firstTestimonial->testimonialReviewee; ?></i></p>
    </div>
</div>

<div class='container'>
    <div class='row'>
        <div class='col-6'>
            <?php foreach($testimonials as $index => $testimonial): ?>
                <?php if($index == ceil(count($testimonials) / 2)): ?>
                    </div>
                    <div class='col-6'>
                <?php endif; ?>
                <h2 class='py-3'><?= $testimonial->title; ?></h2>
                <p><?= $testimonial->testimonialBody; ?></p>
                <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p>
            <?php endforeach; ?>
        </div>
    </div>
</div>

 

  • Like 5
Link to comment
Share on other sites

Thanks :D I was thinking of a way avoid repeating that block twice when only the array differs between the two. Not 100% on what these lines do though, using a key=>value instead of the way I did it:

Just now, Robin S said:

<?php foreach($testimonials as $index => $testimonial): ?>
<?
php if($index >= count($testimonials) / 2): ?>

What's the value of $index here for each loop? This code confuses me somewhat with the div placement. Nice and short though, I like it!

I also extended it now to include a page ref field in the repeater:

1.thumb.png.2395660e89e5e5a19eda5f29196fe5a9.png

 

...so you can choose which site the review came from (with the site title and URL stored in a different template)...

2.png.7327cfbb517c5bfc5902ac57c55c3724.png

...works quite well, and having the reviews out of the standard 3 across grid looks so much better to me.

3.thumb.png.9628de21b9aaf59c3eb20a3e0eb129aa.png

 Glad to be back using PW. Paid job this one.

  • Like 1
Link to comment
Share on other sites

18 minutes ago, SamC said:

What's the value of $index here for each loop? This code confuses me somewhat with the div placement. Nice and short though, I like it!

$index is the key of the array item, which in the case of a PageArray like this is the zero-based index of the item in the array. So it starts at 0 and goes up with each subsequent item.

The "</div><div class='col-6'>" portion is where we end the first column and start the second column. There was an error in my code which I have corrected now - we only want this inserted once, when $index matches half the number of items in $testimonials rounded up to the nearest whole number.

  • Like 2
Link to comment
Share on other sites

Thanks for the explanation @Robin S, you're a gent! I understand it now, final code:

<?php namespace ProcessWire; ?>

<?php
    $testimonials = $page->testimonials;
    $testimonials->shuffle();
    $firstTestimonial = $testimonials->shift();
?>

<div class="jumbotron jumbotron-fluid bg-color">
    <div class="container">
        <h2><?= $firstTestimonial->title; ?></h2>
        <p><?= $firstTestimonial->testimonialBody; ?></p>
        <p class="font-weight-bold">
            <i><?= $firstTestimonial->testimonialReviewee; ?>
                - Review from <a href='<?= $firstTestimonial->reviewSitePageRef->reviewSiteURL; ?>' target='_blank'>
              <?= $firstTestimonial->reviewSitePageRef->title; ?></a>
            </i>
        </p>
    </div>
</div>

<div class='container'>
    <div class='row py-5'>
        <div class='col-sm-12 col-md-6 px-lg-5'>
            <?php foreach($testimonials as $index => $testimonial): ?>
                
                <?php if($index == ceil(count($testimonials) / 2)): ?>
                    </div>

                    <div class='col-sm-12 col-md-6 px-lg-5'>
                <?php endif; ?>
                
                <h2 class='py-3'><?= $testimonial->title; ?></h2>
                <p><?= $testimonial->testimonialBody; ?></p>
                <p class="font-weight-bold">
                    <i><?= $testimonial->testimonialReviewee; ?>
                    - Review from <a href='<?= $testimonial->reviewSitePageRef->reviewSiteURL; ?>' target='_blank'>
                      <?= $testimonial->reviewSitePageRef->title; ?></a>
                    </i>
                </p>
            <?php endforeach; ?>
        </div>
    </div>
</div>

I see that shift() removes the first item of an array and returns it so seems a neat way to extract the first item leaving the rest in the original array. Found the guide here: https://processwire.com/api/arrays/page/

Anyway, thanks again :) 

 

On a side note, I also found a 404 on the PW site where I would have expected a page:

1) Go to https://processwire.com/api/ref/
2) Choose something from dropdown, say $page, takes you here: https://processwire.com/api/ref/page/
3) Back to dropdown, choose 'API Reference...' at the very top  (I wanted to go back to the root at https://processwire.com/api/ref/ )
4) Takes you here instead: https://processwire.com/api/ref/class-loader/API Reference …

Maybe someone can have a look. Might be intended behaviour but thought I'd mention it.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...