Jump to content

Optimisation tips, please...

Recommended Posts


I've been struggling ALL day on my loading time problem and I'm stuck... As I said somewhere else on the Forum, I'm discovering TracyDebugger module to try and help me (and it does help !), but I'm still in a dead-end.

Tracy told me one of my page loads about 4,500 pages and I can't find any way to make it less (and let me tell you that my website is far from having so many users/visitors or whatever, it's just a teacher's website to try to work differently in class).

I have a feeling I am mis-understanding some concepts here. The page can be seen there : http://planetalert.tuxfamily.org/players/4d (for example, but the problem is the same for all teams in my site). As you can see, there are many information on this page, but not that much either I guess for a computer, but it takes 20 seconds to load ! It feels like my page loads just about EVERYTHING that resides in the backend, but I just can't understand by looking a tmy code. For example, the little green and red circles next to the player's names show the actions that have been saved on the last day (so usually 3-5 actions at most, except for players doing online exercises who may have 10 actions). My query is :

    $lastEvent = $player->child("name=history")->children("sort=-date")->first();
    // Get all events on same day
    $prevDay = date("m/d/Y", $lastEvent->date);
    $prevDate = $prevDay.' 0:0:0'; // Select events for the whole day
    $prevEvents = $player->child("name='history'")->children("date>=$prevDate");
    $trend = '';
    foreach ($prevEvents as $event) {
      $HP = $event->task->HP;
      $title = $event->task->title;
      if ($HP < 0) {
        $trendClass = 'negativeTrend';
      } else {
        $trendClass = 'positiveTrend';
      if ($event->summary !== '') {
        $summary = ' ('.$event->summary.')';
      } else {
        $summary = '';
      $trend .= '<span class="'.$trendClass.'" data-toggle="tooltip" data-html="true" title="'.strftime("%d/%m", $event->date).': '.$title.$summary.'">&nbsp;</span>';

But in Tracy pages, I see that the COMPLETE history for EACH player is loaded ! I thought my code was limiting it to the events appearing on the same day as the last saved event. Do you see where I am wrong ?

What's more : I feel like I must do the same mistake for the players (they are all in althought I'm limiting to the particular team). I must say though, that I'm caching (supposively) ALL players when Admin is logged in so he can have a faster access in the top menu.

More? All places and people that players can free are loaded as well. Why is this? I just want to load the places and people that are actually freed by players and show the names (not complete info). I'm not putting an example of the code here because I have a feeling the problem resides in my way of organising the complete thing... and that's what worries me the most... Maybe it's gonna be hard for one of you to understand (and have the time) my awkward way of organizing things (even though I'm trying hard to be well-organized ;) ). So I'd rather point to the Github repository : https://github.com/celfred/PlanetAlertProfile/tree/master/site/templates

The file I'm talking about above is team.inc.php. It is included in list-all.php which includes head.inc and foot.inc as well.

Things have changed quite a bit on my local site today, but I'm getting in such a mess that I'd rather not commit to remote. I've corrected some things, but what I have just explained above is still there :(

While I'm at it. Other page, other problem detected : my adminTable.php page which you can a look at at : http://planetalert.tuxfamily.org/players/adminTable/4d (I've just noticed that it should be acess restricted, but nevermind for today, don't submit just in case I forgot other things... _ yes, I'm desperate tonight...) and which submits to submitForms.php. Well, I had to put AJAX request for that because it was running into a timeout because of the loading time. It worked (althought I ended up waiting 30 seconds to record my table !) but today, Tracy and debug ON showed me the 'Maximum 100 nested functions limit fatal error' after hours of research, I endend up... writing this post :( I know my function updateScore() (in my-functions.php) is difficult, but what?? It just updates the scores depending on the task being recorded then checks the impact on other players and if it does have an impact, it triggers itself back to update the score of that other player. But yes, I know it can be some sort of never-ending story, but how can I do differently ? I wonder if it's ok to have wire('pages') in so many of my functions. But again, how can I do in another way?

Well, sorry for such a long post, folks, but as you can understand, I'm facing a wall here and I hope someone around here will find some time to try and find his or her way into my code and give me a hint on where I could improve.

I have had so many help from this community in the past and it felt such a relief and a revelation (Ended up telling my wife : "Wow, it looks so simple for these guys ! I've spent so many hours on that and... Of course ! Now I get it !! I'm getting better ! No next time !")

Well, today is a 'next time'...

Thanks if you've read up to this point and THANKS if you go and have a look at my code !


Share this post

Link to post
Share on other sites

Yeah, that's a lot of post :P. Let's see if we can take it bit by bit.

I believe this line will grab ALL the children (a PageArray) of history from the database, then return the first (in-memory manipulation) of these retrieved results:

$lastEvent = $player->child("name=history")->children("sort=-date")->first();

Instead, try this, to actually grab ONLY one child from the database:

$lastEvent = $player->child('name=history')->child('sort=-date');

This line doesn't make sense to me:

$prevEvents = $player->child("name='history'")->children("date>=$prevDate");

How can previous events' date be greater than the previous date?

  • Like 4

Share this post

Link to post
Share on other sites

Thanks @kongondo for the 1st tip. I get the difference between children('-date')->first() and child('-date'). Although I've just tried to change this line and nothing changed in my Tracy 'Processwire Debug' panel... still many many loaded pages... I'll dig that later when I have more time. Maybe I have the same kind of error somewhere else...

About the date>=$prevDay : this solved an issue I had because of the time appended to the date. Actually in my code, I take the last event, get the date, change the time to 0:0:0 and eventually get the >= to find all those events having the same day, but with a superior time. Maybe (I'm sure actually...) there's a better solution. I remember at the time I implemented this, I was surprised not to be able to retrieve the same day events and this was the only workaround I found :)

Share this post

Link to post
Share on other sites

In the frontend, have you checked to see how many pages are being retrieved? Something like this:

$prevEvents = $player->child("name='history'")->children("date>=$prevDate");
echo $prevEvents->count();// does this output the number of pages you are expecting?

In addition, any repeaters in the fields you are retrieving?

  • Like 1

Share this post

Link to post
Share on other sites

The $prevEvents->count() is fine. This part works as expected :)

Your post reminded me of trying to cut down through my page to see where the ALL pages request was (ou could be), and reducing things little by little, I saw my checkStreak() function in which I look over the history of each player ti find if the last 10 consecutive events are positive, in which case the player becomes an 'AMbassador' and here was my code :

  $lastEvents = $player->get("name=history")->find("template=event, sort=-date")->not("task.name=donated|donation|absent, limit=10");

I bet you can see right through it : the 'limit=10' is misplaced and useless where it is !!! The code should be (I think) :

  $lastEvents = $player->get("name=history")->find("template=event, sort=-date, limit=10")->not("task.name=donated|donation|absent");

Now my 'loaded page' is reduced to about 480. What a gain ! And this checkStreak() function is called each time I save a new event for a player (to check if he needs to become an ambassador...)

So I'll keep digging because I can imagine I have the same sort of mistake at other places, but I am already glad of this improvement.

So thanks a lot !

Share this post

Link to post
Share on other sites
// Returns 10 pages, which are then further filtered, so it could even be none
$lastEvents = $player->get("name=history")->find("template=event, sort=-date, limit=10")->not("task.name=donated|donation|absent");
// Returns 10 of the correct pages
$lastEvents = $player->get("name=history")->find("template=event, sort=-date, limit=10, task.name!=donated|donation|absent");

Not sure what behaviour you want there, but there's a difference.

  • Like 2

Share this post

Link to post
Share on other sites

I feel a little dumb once again... Your explanation is perfect and I guess I want the 2nd one. I think I was mistaken on that 'not()' filter. I'll have to check everywhere I've used it.

The 'further filtered' was the key in your explanation. Thanks !

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 daniel_puehringer

      so we all know about SEO and the importance of performance. Basically we do it, because if no one finds the website we just built, it´s frustrating. We all try to write clean markup, css and js code and most might have a webpack/gulp/whatever pipeline to minimize css&js.
      But when thinking about it, optimizing your pipeline might save you a few (hundreds) of kb, compared to loading an image with 1 mb that´s literally nothing and frankly just ridiculous.

      Don´t get me wrong, frontend pipelines are great and should be used, but let´s shift your "I will optimize the shit out of that 3 css lines" focus to something different: try to serve images as fast as possible, this is where the performance boost really happens.

      I´m no pro on processwire so far, but I built a very easy to use picture element, which some of you could find interesting:

      1. the picture comes with 3 different sizes: one for mobile (keep in mind the double dpi, therefore width of 828px), one for tablet and one for desktop
      2. the picture generates a webp version and the original file extension as a fallback
      3. the filesize of each element is rendered within the "data" attribute
      4. lazy loading(sooo important!!!) is done via the native 'loading="lazy"' attribute.

      Please try it out and see the difference 🙂

      I posted this so others can easily optimize their images, but I would also like to hear your suggestions in making it better. Maybe you could decrease the rendering time or maybe you have some easy improvements.

      Please let me know.

      Greetings from Austria!

      <picture> <source data="<?php echo($oElement->repeater_image->width(828)->webp->filesize);?>" media="(max-width: 414px)" srcset="<?php echo($oElement->repeater_image->width(828)->webp->url) ?> 2x" type="image/webp"> <source data="<?php echo($oElement->repeater_image->width(828)->filesize) ?>" media="(max-width: 414px)" srcset="<?php echo($oElement->repeater_image->width(828)->url) ?> 2x" type="image/<?php echo($oElement->repeater_image->ext)?>"> <source data="<?php echo($oElement->repeater_image->width(767)->webp->filesize) ?>" media="(min-width: 415) and (max-width: 767px)" srcset="<?php echo($oElement->repeater_image->width(767)->webp->url) ?> 2x" type="image/webp"> <source data="<?php echo($oElement->repeater_image->width(767)->filesize) ?>" media="(min-width: 415) and (max-width: 767px)" srcset="<?php echo($oElement->repeater_image->width(767)->url) ?> 2x" type="image/<?php echo($oElement->repeater_image->ext)?>"> <source data="<?php echo($oElement->repeater_image->webp->filesize) ?>" media="(min-width: 768px)" srcset="<?php echo($oElement->repeater_image->webp->url) ?>" type="image/webp"> <source data="<?php echo($oElement->repeater_image->filesize) ?>" media="(min-width: 768px)" srcset="<?php echo($oElement->repeater_image->url) ?>" type="image/<?php echo($oElement->repeater_image->ext)?>"> <img data="<?php echo($oElement->repeater_image->filesize) ?>" class="img-fluid" loading="lazy" src="<?php echo($oElement->repeater_image->url) ?>" alt="<?php echo($oElement->repeater_image->description) ?>" type="image/<?php echo($oElement->repeater_image->ext)?>"> </picture>
    • By David-M
      anyone, any ideas how to solve? 
      i get following error on a website:
      Notice: Undefined variable: out in /var/sites/i/islandmemorials.co.uk/public_html/site/templates/includes/functions.php on line 43
      and this is a code in that very functions file:
      <?php function numberOpen() { date_default_timezone_set("Europe/London"); $currentHour = date('G'); if($currentHour > 9 && $currentHour < 21) { $openFor = 21 - $currentHour; if($openFor > 1) { echo "We're currently open for another ".$openFor." hours, why not pop in?"; } else { echo "Our lines are open for another hour - <a href=\"tel:+01983 857 600\">01983 857 600</a>"; } } else { echo "Unfortunately, our lines are currently closed, but you can still send a message below"; } } function getSubNav($pid) { $test = wire('pages')->get("/services/"); $parents = wire('page')->parentID; $template = wire('page')->template; $out = ''; //echo "pid".$pid."<BR>"; //echo "parents".$parents."<BR>"; //echo "template".$template."<BR>"; $children = $test->children; foreach($children as $child) { $class = $child->id === $pid ? " active" : 'inactive'; if ($child->id === $pid ) { $class= 'active'; } elseif ($template= "memorials" && $child->id === $parents ) { $class= 'active'; } $out .= "<li><a class='{$class}' href='{$child->url}'>{$child->title}</a></li>"; } return $out; } ?> i suppose this has to do with a variable scope, but not sure
    • By louisstephens
      I am wondering, how do you pass a variable into wire('page')->get() inside a function? I have been looking through the forums, but unfortunately I have not found the answer yet.
      My current set up is:
      function generateNewPages($parentPageName) { $p = new Page(); $p->template = "parent"; $p->parent = wire('pages')->get('/home/'); $p->name = $parentPageName; $p->title = $parentPageName; $p->of(false); $p->save(); $p2 = new Page(); $p2->template = "child"; $p2->parent = wire('pages')->get('$parentPageName'); $p2->name = "child"; $p2->title = "Child Page"; $p2->of(false); $p2->save(); } When I try to run it by passing in a title like generateNewPages('Demo');, "Demo" is created, but when it gets to the child page I get:
      Unknown Selector operator: '$' -- was your selector value properly escaped?
      Is there a way to pass the $parentPageName to "wire('pages')->get('$parentPageName')" ?
    • By celfred
      Another newbie question. My Processwire sites is growing and I'm wondering if my way of doing things sounds goog to you. I tend to avoid what I consider 'heavy and frequent' database requests in my functions. For example :
      // In functions.php myfunction($player) { wire('$pages')->find("myselectors"); // This means about 300 database requests do something... (like $p->newTmpField = 1;) return $player; } // In template.php $allPlayers = $pages->find("template=player"); // About 300 players foreach ($allPlayers as $p) { myfunction($p); } // Now I have access to newTmpField, for example.  I tend to replace with :
      // In function.php myfunction($allPlayers) { foreach($allPlayers as $p) { // do something like set $p->newTmpField = 1 } return $allPlayers; } // In template.php $allPlayers = $pages->find("template=player"); myfunction($allPlayers); // Now $players have been modified. For example, I have $allPlayer->find("newTmpField=1"); So for the moment, I tend to choose the second solution which makes only 1 database request, but what do more experimented developers would recommend ?
      What I find useful with Page objects in functons arguments is that I have the whole 'tree' I can then 'find' in my function. But as you can see, I need to understand things better. I have a feeling my 'practical' explanation is not really convincing 🙂 
      Thanks if someone can take a few minutes to give me advice !
    • By tourshi
      I'm new to PW and still a novice in PHP. I was just wondering how does one access PW within  a function? 
      do I pass the entire $page variable to getTitle()? or do I use global $page within the function...I'm confused.. Especially considering there must be a performance penalty for passing entire page variable when I only need a few variables from it (for example $page->long_title, $page->menu_title, $page->short_title).
      function getTitle() { $long_title = $page->long_title; $title = !empty($long_title) ? $long_title : $page->title; return $title; }
  • Create New...