hollyvalero

Oneforeach loop to rule them all - with image size specified

Recommended Posts

I came across a foreach example that I was able to customize a bit without several error messages. Yes, I am new. Be kind... coming from Modx.  Basically, 80% of what I need in most web development is: bring back a bunch of fields from THIS parent page or THIS template... and display a limited number... sorted by whatever....  home page features, carousels, masonry... it's everywhere

This is a basic sample for news items on a sample home page - 3 across the bottom.  What I can't seem to incorporate is the ability to say:     $img = $image->size(320,180);

No matter what image size has been uploaded, in the display we want it to be 320 px by 240px. I can do the images alone...  foreach($images as $image) but I can't seem to get that into this foreach and I assume it's because I am using $features at the top ... I'd be happy to call it $pages or $penguin or anything...  I just want to keep the ability to use the same thing in about 3-6 locations within a website by changing the template name... since this is a very common function.

Thank you!

$features = $pages->find("template=newsitem, limit=3, sort=-date");

foreach($features as $feature) {

   echo "<div class='column is-4' >" .
        "<img src='{$feature->image->url}' alt='' />" .
        "<h3 class='title is-4'><a href='{$feature->url}'>{$feature->title}</a></h3>" .
        "<p><span class='date'>{$feature->date}   • </span>" .
        "{$feature->summary}</p>" .
        "</div>";

}

 

 

 

 

 

Share this post


Link to post
Share on other sites

This should work:

<?php

$features = $pages->find("template=newsitem, limit=3, sort=-date");

foreach($features as $feature) {
	$img = $image->first()->size(320, 180)->url;
	echo "
		<div class='column is-4' >" .
			"<img src='$img' alt='' />" .
			"<h3 class='title is-4'><a href='{$feature->url}'>{$feature->title}</a></h3>" .
			"<p><span class='date'>{$feature->date} &nbsp; &bull; </span>" .
			"{$feature->summary}</p>" .
		"</div>";
}

You can read more in the docs. On why you should use first() - or not.

  • Like 3

Share this post


Link to post
Share on other sites

Welcome to the forums and ProcessWire :). Oh, we are very kind to everyone, especially those coming from the nightmare that is WordPress. Just kidding. Former MODx-er myself. 

Nothing wrong with using the variable $features. What I suspect is that your image field is set to hold (and return) more than one image, i.e. an array. So, calling the resize function on an array won't work. 

Edit Been beaten by others who are faster at typing/thinking...so will stop typing now :-[:P :)

  • Like 3

Share this post


Link to post
Share on other sites
1 minute ago, kongondo said:

Nothing wrong with using the variable $features. What I suspect is that your image field is set to hold (and return) more than one image, i.e. an array. So, calling the resize function on an array won't work.  

** Actually the field is a single image field called "image" ... used for news features that have one teaser image... 

Share this post


Link to post
Share on other sites
5 minutes ago, arjen said:

This should work:


<?php

$features = $pages->find("template=newsitem, limit=3, sort=-date");

foreach($features as $feature) {
	$img = $image->first()->size(320, 180)->url;
	echo "
		<div class='column is-4' >" .
			"<img src='$img' alt='' />" .
			"<h3 class='title is-4'><a href='{$feature->url}'>{$feature->title}</a></h3>" .
			"<p><span class='date'>{$feature->date} &nbsp; &bull; </span>" .
			"{$feature->summary}</p>" .
		"</div>";
}

You can read more in the docs. On why you should use first() - or not.

 

 

So this gives me:  Call to a member function first() on a non-object (line 7  -- which is the line:

$img = $image->first()->size(320, 180)->url;

And most of my errors seemed to be like this.  The field is a single image field, not a multiple image field.

Share this post


Link to post
Share on other sites

We didn't define the $image variable. How about this?

<?php

$features = $pages->find("template=newsitem, limit=3, sort=-date");

foreach($features as $feature) {
	$img = $feature->image->size(320, 180)->url;
	echo "
		<div class='column is-4' >" .
			"<img src='$img' alt='' />" .
			"<h3 class='title is-4'><a href='{$feature->url}'>{$feature->title}</a></h3>" .
			"<p><span class='date'>{$feature->date} &nbsp; &bull; </span>" .
			"{$feature->summary}</p>" .
		"</div>";
}
  • Like 3

Share this post


Link to post
Share on other sites
1 minute ago, arjen said:

We didn't define the $image variable. How about this?


<?php

$features = $pages->find("template=newsitem, limit=3, sort=-date");

foreach($features as $feature) {
	$img = $feature->image->size(320, 180)->url;
	echo "
		<div class='column is-4' >" .
			"<img src='$img' alt='' />" .
			"<h3 class='title is-4'><a href='{$feature->url}'>{$feature->title}</a></h3>" .
			"<p><span class='date'>{$feature->date} &nbsp; &bull; </span>" .
			"{$feature->summary}</p>" .
		"</div>";
}

YAY!!  That worked!!!  Thank you!

 

 

Share this post


Link to post
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


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By louisstephens
      So I have a bit of code for ad management :
      <?php $ads = $pages->find("parent.template=client, sort=expiration_date"); $alert_count = 0; foreach ($ads as $ad) { $todaysdate = date("F j, Y H:i"); $today = strtotime($todaysdate); $expireson = $ad->expiration_date; $expires = strtotime($expireson); $fiveaway = $expires - 432000; if ($today > $expires) { $alert = $alert_count=+1; echo $alert; } } //end FOREACH ?> It currently finds all the pages with a parent of "client" and then I can drill down to the pages that have "Expired" in my if statement. I wanted to get a "count" of the pages that met the if statement requirements so I could output that number in an alert at the top of the page. When it runs, it currently just prints out "1 1 1 1..." and not the total count of pages. Does anyone know of a way possibly achieving my desired output? I tried count(), but that did not quite produce my desired output.
       
      I should note that I have several other if statements dealing with the date/time for outputting other alerts as well (just didn't think they were needed for this case).
    • By creativejay
      My brain is probably just tiring out on me right this moment, I'm hoping that by the time I write out my problem I'll see the way through it. If you're reading this, it didn't work.
      Structure in question is:
      Series Page Product pages Page Fields for each product page Some of these fields are repeaters Fields within the repeater I have made an array of page fields so I don't have to keep track of them all as I develop:
      $listings = $page->children; // grab all the published children of the Series page foreach($listings as $l) { // loop through the children foreach($l->fields as $f) { } // loop through each child's page fields where they have a value set } Then I break down how to handle each type of field:
      if($f->type == 'FieldtypeFile') { } elseif($f->type == 'FieldtypeDatetime'||$f->name == 'prod_status_pages'||$f->type == 'FieldtypeImage'){ } elseif($f->type == 'FieldtypePage'){ } These are all largely working as expected (though I do have a couple of offset/isset exceptions to clean up...)
      It's when I get to the repeaters that I run into trouble getting the API calls to work.
      Just cycling through the fields as above, the output for a FieldtypeRepeater is the ID of the repeater in that field's array. Everything I read suggests I should treat a repeater the same as I would treat a page, which leads me to the following code.
      elseif($f->type == 'FieldtypeRepeater'){ // Repeaters need special treatment otherwise output is just ID $th .= "<th><b>{$f->label}</b></th>\n"; $trows = ""; // creating an empty variable to build my foreach into foreach($f->fields as $rf){ // looping, I hope, through the fields of the given Repeater ID $trows .= "{$rf->label}: {$f->get($rf)->title} ({$rf->type})<br />\n"; // add an entry to the variable } $rows .= "<td style='padding: 8px 16px; vertical-align: middle;'>".$trows."<br />\n ({$f->type})</td>\n"; // back out to rendering the Repeater field }  
      What I would hope would output in the HTML I've been building is something like:
       
      <td style='...'>Lo temp: -40 (Integer)<br /> Hi temp: 75 (Integer)<br /> Storage Lo: -40 (Integer)<br /> Storage Hi: 85 (Integer)<br /> Functional to: 85 (Integer)<br /> (FieldtypeRepeater)</td> So what I'm trying to do here is loop through the populated fields in the unknown Repeater field, and output them as a simple (so far) text list of the repeater.field and its value (and then its type for my reference).
      I'm afraid typing this out has fixed some syntax but not enough to get this working as I'd hoped.
      Please note not all Repeater fields are integers. Some also have floats, files, or options, and probably a couple others I'm forgetting.
       
      I appreciate your time in taking a look at this!
    • By louisstephens
      I have a foreach loop on a dashboard page where I sorting the pages titles to different columns based on a date field. Unfortunately, I am doing it with multiple different if statements for the sorting (with multiple foreach loops), as I needed something quickly for testing. I thought it would be nice to implement wireSMTP to send an email out to alert the users that created the pages, which I got working in no time. However, now I have hit a roadblock. The dashboard page has a javascript function that refreshes the page every few hours to get the changes in the date, which then triggers the $mail to fire the email out. 
      I guess my question is there a way to limit the emails to be sent out only once the date/time has changed once instead of it firing every time the page refreshes?
    • By MilenKo
      Hello all. Yesterday working on my Cooking Recipes profile I stumbled across an interesting issue - how to show pages published/created on a specific time interval without the use of any plugins but just the default API of PW. Thanks to @abdus the sollution was implemented and was working perfectly fine (here)
      Everything was good until I started working on my main page and discovered that our web designer made the recipes appear in threee columns and to differentiate the columns he used 3 different classes (first, second, last). So it was supposed to look like this:
      <li><class="cs-recipes first"></li>     |     <li><class="cs-recipes second"></li>     |     <li><class="cs-recipes last"></li>
      At first I thought it would be easy to just create another loop and insert it within the first one, but that got me unprepared as instead of 5 posts (as the limit was), I was showing 15. So moving here and there, trying and trying for quite some time to find a solution, I got stuck and asked for some help. Mr @abdus saved the day again offering something simple and most important - fully working. As far as it was a PM, I decided that it would be a shame if I don't share it with anybody else who might sooner or later search for similar functionality, so here is the complete sollution that works perfectly fine and applies the first, second, last as it should without creating unnecessary loops etc.:
      Hope it helps and don't thank me, I am just the messenger
    • By lecrackffm
      Hello everyone, 
      i have written a simple function to render the Navigation for my "Onepager"
      Here is the code: 
      <?php function renderOnepagenav($onepageroot) { $sections = $onepageroot->children; echo "<ul>"; $id = ''; foreach ($sections as $item) { $id ++; echo "<li><a href='#section-$id'>$item->title</a></li>"; } echo "</ul>"; } Every Sektion is a child-page of home in the backend.
      It works fine but i would like to add two modifications, where i need your help:
      1.  i would like to skip the first  (child-)page.
      2. I would like to add a class only to the first  rendered <li>  Element.
       
      All kind of advice is highly appreciated.
      Thank you, 
      Gregor