SamC Posted January 18, 2018 Share Posted January 18, 2018 I was looking at the uikit menu issues here: ...when I stumbled across something weird that I can't get my head around. I'll paste in the code I used again to save checking that link out and the two commented parts of code I'm talking about: <?php /* // when this is used, dropdown under 'Home' has NO home link $root = $pages->get("/"); $children = $root->and($root->children); // echo $children: 1|1086|1069|1081|1022 */ ?> <?php /* // when this is used, dropdown under 'Home' HAS home link $root = $pages->get("/"); $children = $root->children(); // insert the following line $children->prepend($root); // echo $children: 1|1086|1069|1081|1022 */ ?> <nav class="uk-navbar-container" uk-navbar> <div class="uk-navbar-left"> <ul class="uk-navbar-nav"> <?php foreach($children as $c):?> <li> <a href="#"><?= $c->title; ?></a> <div class="uk-navbar-dropdown uk-navbar-dropdown-width-2 g8-theme-mkred"> <div class="uk-navbar-dropdown-grid uk-child-width-1-2" uk-grid> <ul class="uk-nav uk-navbar-dropdown-nav"> <?php foreach($c->children as $cc):?> <li><a href="<?= $cc->url ?>"><?= $cc->title ?></a></li> <li class="uk-nav-divider"></li> <?php endforeach; ?> </ul> </div> </div> </li> <?php endforeach; ?> </ul> </div> </nav> Can anyone tell me what the difference is between the two commented parts at the top? Both $children variables appear to have the same pages but one results with no home link in the dropdown. However, using either of the versions, the top level menu is the same. Home | About | Services | Portfolio | Contact Can't get my head around this. I would expect both dropdowns not to have the 'Home' link. Any ideas? Link to comment Share on other sites More sharing options...
qtguru Posted January 18, 2018 Share Posted January 18, 2018 I can't comment about the first because I don't fancy that pattern but the second think about it as a stack by prepending, you're pushing the items from the top when adding compared than from the bottom. Link to comment Share on other sites More sharing options...
kongondo Posted January 18, 2018 Share Posted January 18, 2018 2 hours ago, SamC said: Can anyone tell me what the difference is between the two commented parts at the top? I've tested your code and the outputs are identical. Must be something else you are doing? 2 hours ago, SamC said: Can't get my head around this. I would expect both dropdowns not to have the 'Home' link. Why? In the first (using and()), you are adding children to the existing item (Home). In the second, you get the children and prepend their root (Home) to them. Side note: What I don't understand is why and() has worked with the single page object ($root). I thought (as per docs) it should only work with WireArrays (also PageArrays). $root is a Page not a PageArray, or am I missing something? Link to comment Share on other sites More sharing options...
SamC Posted January 18, 2018 Author Share Posted January 18, 2018 12 minutes ago, kongondo said: Why? In the first (using and()), you are adding children to the existing item (Home). In the second, you get the children and prepend their root to them. It's the dropdowns in the inner loop that are different: <?php // Home, About, Services, Portfolio, Contact foreach($children as $c): ?> <li> <a href="#"><?= $c->title; ?></a> <div class="uk-navbar-dropdown uk-navbar-dropdown-width-2 g8-theme-mkred"> <div class="uk-navbar-dropdown-grid uk-child-width-1-2" uk-grid> <ul class="uk-nav uk-navbar-dropdown-nav"> <?php // Children of home, Children of about, children of services... foreach($c->children as $cc): ?> <li><a href="<?= $cc->url ?>"><?= $cc->title ?></a></li> <li class="uk-nav-divider"></li> <?php endforeach; ?> </ul> </div> </div> </li> <?php endforeach; ?> I have no idea why one version (with the prepend), the dropdown under home is: Home ---- Home About Services Portfolio Contact ...and the other version (using and()): Home ---- About Services Portfolio Contact The dropdowns under 'Services' however are the same with both versions. The differences only affect the 'Home' dropdown. 12 minutes ago, kongondo said: What I don't understand is why and() has worked with the single page object ($root). I thought (as per docs) it should only work with WireArrays (also PageArrays). $root is a Page not a PageArray, or am I missing something? Beats me, but I've used this a few times. Link to comment Share on other sites More sharing options...
Robin S Posted January 18, 2018 Share Posted January 18, 2018 1 hour ago, kongondo said: What I don't understand is why and() has worked with the single page object ($root). I thought (as per docs) it should only work with WireArrays (also PageArrays). $root is a Page not a PageArray, or am I missing something? It's the WireData::and() method. Was a new one to me too. 1 Link to comment Share on other sites More sharing options...
kongondo Posted January 18, 2018 Share Posted January 18, 2018 1 hour ago, SamC said: I have no idea why one version (with the prepend), the dropdown under home is: Home ---- Home About Services Portfolio Contact ...and the other version (using and()): Home ---- About Services Portfolio Contact Because you are calling both code at the same time . Comment out the first (the one using and() AND it will work). An object is already in memory and PHP has a reference to it, so the items are added to the original object....or something like that...I am a bit knackered, sorry, can't give a better explanation . Link to comment Share on other sites More sharing options...
kongondo Posted January 18, 2018 Share Posted January 18, 2018 14 minutes ago, Robin S said: It's the WireData::and() method. Was a new one to me too. Nice find! . Link to comment Share on other sites More sharing options...
SamC Posted January 18, 2018 Author Share Posted January 18, 2018 23 hours ago, kongondo said: Because you are calling both code at the same time Lol, I wish. I just stuck them in that example above to show the two differences. Running them separately causes the issue. <?php $root = $pages->get("/"); $children = $root->children(); // insert the following line $children->prepend($root); ?> ...gives me: Home ---- Home About Services Portfolio Contact and (even with changing the variable name in case of it being in memory already): <?php $root = $pages->get("/"); $children2 = $root->and($root->children); ?> ...gives me: Home ---- About Services Portfolio Contact The only way I can get 'Home' into the dropdown in this example is to add it in the inner loop: <?php foreach($homepage->and($c->children) as $cc):?> ...gives me: Home ---- Home About Services Portfolio Contact Is the weirdest thing. == EDIT == Been looking at these again tonight, tried the following on my demo site. The WireArrays are different (one is larger) for each $topLevels variable (depending on which one you uncomment). <?php $root = $pages->get("/"); // Home link in inner loop // $topLevels = $root->children->prepend($root); // NO Home link in inner loop // $topLevels = $root->and($root->children); ?> <ul> <?php foreach($topLevels as $topLevel):?> <li> <a href="#"><?= $topLevel->title; ?></a> <ul> <?php foreach($topLevel->children as $topLevelChild): ?> <li><a href="<?= $topLevelChild->url ?>"><?= $topLevelChild->title ?></a></li> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul> I get (top option): Home - Home - About - Services - Contact - Cats - Type ...and (second option):: Home - About - Services - Contact - Cats - Type I would expect no home link to be in either and the resulting WireArrays in '$topLevels' to be the same. The inner loop, loops through the children of the top level page, 'Home' should not be in there twice It's something to do with the resulting WireArrays of those two lines. Am I just being super slow here or what? Link to comment Share on other sites More sharing options...
webhoes Posted January 23, 2018 Share Posted January 23, 2018 In both cases you add $root (home or page 1) to the array. That is why they appear. You could hardcode the link to home and after that make a foreach for the children of $pages->get("/"). You don't have to do fancy tricks to add home like and or prepend. Link to comment Share on other sites More sharing options...
webhoes Posted January 23, 2018 Share Posted January 23, 2018 Something like this <nav class="uk-navbar-container" uk-navbar> <div class="uk-navbar-left"> <ul class="uk-navbar-nav"> <?php $root = $pages->get("/"); echo "<li><a href="/">Home</a></li>"; foreach($root->children as $child){ echo "<li><a href=" . $child->link . ">" . $child->title . "</a>" if(count($child->children>0)){ echo "<div class="uk-navbar-dropdown uk-navbar-dropdown-width-2 g8-theme-mkred"> <div class="uk-navbar-dropdown-grid uk-child-width-1-2" uk-grid> <ul class="uk-nav uk-navbar-dropdown-nav">"; foreach($child as $c) { echo "<li><a href=" . $c->url . ">" . $c->title . "</a></li>"; } echo "</ul>"; } } ?> </ul> </div> </nav> Link to comment Share on other sites More sharing options...
kongondo Posted January 23, 2018 Share Posted January 23, 2018 27 minutes ago, webhoes said: In both cases you add $root (home or page 1) to the array. That is why they appear. The issue is that for Sam, in the first code, "Home" appears twice, for some reason. I wasn't able to replicate that. I have a strong feeling that some other code is contributing to that anomaly. Link to comment Share on other sites More sharing options...
webhoes Posted January 23, 2018 Share Posted January 23, 2018 I see now... did not read carefully enough though the whole thread... Link to comment Share on other sites More sharing options...
SamC Posted January 23, 2018 Author Share Posted January 23, 2018 Tried same code, two different sites, one of which is nearly a fresh install with exactly the same issue. If the outer loop, loops through the top level pages (including home) and the inner loop loops through the children of the top level pages, home should never be output inside the inner loop, but it does for some reason. This only happens using: <?php $topLevels = $root->children->prepend($root); ?> <ul> <?php foreach($topLevels as $topLevel):?> <li> <a href="#"><?= $topLevel->title; ?></a> <ul> <?php foreach($topLevel->children as $topLevelChild): ?> <li><a href="<?= $topLevelChild->url ?>"><?= $topLevelChild->title ?></a></li> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul> There's literally no other code affecting this. Nothing in '_init.php' (which I do prepend) and this is just direct output. Check out the resulting WireArrays for these two variables ($topLevels and $topLevels2): <?php $root = $pages->get("/"); $topLevels = $root->children->prepend($root); $topLevels2 = $root->and($root->children); ?> They're not the same. This isn't an important issue, but I'm curious I can't see any errors in the code, or any other code that would affect this throughout the site. 1 Link to comment Share on other sites More sharing options...
BitPoet Posted January 23, 2018 Share Posted January 23, 2018 Yes, this is somewhat unexpected behavior and can be replicated with a short piece of code: $r = $pages->get('/'); $x = $r->children; $y = $r->children; $z = $r->children->prepend($r); echo $x . PHP_EOL; echo $y . PHP_EOL; echo $z . PHP_EOL; This outputs here: 1001|1005|1025 1|1001|1005|1025 1|1001|1005|1025 This illustrates that consecutive calls to children() return a pointer to the original PageArray while the very first call returns an independent copy. That's likely a caching thing, though I can't say if this is expected behavior. Tested with different versions of PW. 4 Link to comment Share on other sites More sharing options...
Robin S Posted January 23, 2018 Share Posted January 23, 2018 1 hour ago, BitPoet said: This illustrates that consecutive calls to children() return a pointer to the original PageArray while the very first call returns an independent copy. And it's not just children() but other (all?) methods that use PageFinder: Weird. 1 Link to comment Share on other sites More sharing options...
SamC Posted January 23, 2018 Author Share Posted January 23, 2018 1 hour ago, BitPoet said: This outputs here: 1001|1005|1025 1|1001|1005|1025 1|1001|1005|1025 This illustrates that consecutive calls to children() return a pointer to the original PageArray while the very first call returns an independent copy. Aha! thanks @BitPoet Link to comment Share on other sites More sharing options...
kongondo Posted January 23, 2018 Share Posted January 23, 2018 Hmm. Then I must be going mad. Using the original code by @SamC, (even together/at the same time), I get identical output! Could someone please try the following and let me know if you get different/same output? Even if I comment out the 2nd $pages->get('/'), it makes no difference // code 1 $root = $pages->get("/"); $children = $root->and($root->children); echo $children . '<br><hr>';// outputs >>> 1|1001|1005|1137 // code 2 $root = $pages->get("/"); $children = $root->children; $children->prepend($root); echo $children . '<br>';// outputs >>> 1|1001|1005|1137 exit; ProcessWire 3.0.85, home.php (at the very top, exit after code) Link to comment Share on other sites More sharing options...
adrian Posted January 23, 2018 Share Posted January 23, 2018 I haven't been following the conversation, but if it helps, here is what I see with @kongondo's code: Link to comment Share on other sites More sharing options...
kongondo Posted January 23, 2018 Share Posted January 23, 2018 (edited) Thanks for testing @adrian! The code is from the OP. However, the OP, @SamC, is getting different results with the very same code. Similar to yours, here's my Tracy console output: The output is identical Edited January 23, 2018 by kongondo Link to comment Share on other sites More sharing options...
SamC Posted January 23, 2018 Author Share Posted January 23, 2018 1 hour ago, kongondo said: I get identical output! Yeah that's why it's so weird. I did too! Check my original post, the ids output are: 1|1086|1069|1081|1022 ...for both versions. However, it's the returned WireArrays that are different (check them with print_r ()). One version gives me an added 'Home' link but in order for that to be output in the inner loop, it must have been added to the children of home as the outer loop is correct. If 'Home' was added as an extra parent, then the outer loop would have output : Home|Home|About|Services|Portfolio|Contact It's like there's a wirearray inside a wirearray. Link to comment Share on other sites More sharing options...
kongondo Posted January 23, 2018 Share Posted January 23, 2018 5 minutes ago, SamC said: However, it's the returned WireArrays that are different (check them with print_r ()). I have checked. The WireArrays are identical as well. Each with the same 4 items. Link to comment Share on other sites More sharing options...
Robin S Posted January 24, 2018 Share Posted January 24, 2018 (edited) 3 hours ago, kongondo said: Hmm. Then I must be going mad. Using the original code by @SamC, (even together/at the same time), I get identical output! The thing is, that isn't the code from the OP. To experience the issue I believe you need to have a minimum of three usages of the same PageFinder operation (in this case, getting the children of the root page). In SamC's original code there were two usages where the children of root are retrieved (showing different alternatives for doing the same thing) and then a third usage of the children of root within the foreach that generates the dropdown menu. An explanation of what I believe is going on (to the extent that I understand it): Edited January 24, 2018 by Robin S corrected screenshot 3 Link to comment Share on other sites More sharing options...
BitPoet Posted January 24, 2018 Share Posted January 24, 2018 7 hours ago, kongondo said: Then I must be going mad I don't think so. But I believe that you don't have the exactly same setup as @SamC, in which something, somewhere (a module, a prepend file, site/ready.php, whatever), already retrieves the children once before the code we see is executed. It's the only thing that makes sense. If you repeat code 2 in your test script, you'll get an output starting with 1|1|..., I'm pretty sure of that, so you can see the how, just not the where. 4 Link to comment Share on other sites More sharing options...
SamC Posted January 24, 2018 Author Share Posted January 24, 2018 Just tried this morning on a completely fresh install, no prepended files, no extra modules etc. Created a basic structure just with basic page and included "_main-menu.php" which shows the issue of running $pages->children twice: <?php namespace ProcessWire; $root = $pages->get("/"); $topLevelsFirst = $root->children(); $topLevels = $root->children(); $topLevels->prepend($root); ?> <ul> <?php foreach($topLevels as $topLevel):?> <li> <a href="<?= $topLevel->url ?>"><?= $topLevel->title; ?></a> <ul> <?php foreach($topLevel->children as $topLevelChild): ?> <li><a href="<?= $topLevelChild->url ?>"><?= $topLevelChild->title ?></a></li> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul> ..which outputs: ...and <?php namespace ProcessWire; $root = $pages->get("/"); $topLevels = $root->children(); $topLevelsSecond = $root->children(); $topLevels->prepend($root); ?> <ul> <?php foreach($topLevels as $topLevel):?> <li> <a href="<?= $topLevel->url ?>"><?= $topLevel->title; ?></a> <ul> <?php foreach($topLevel->children as $topLevelChild): ?> <li><a href="<?= $topLevelChild->url ?>"><?= $topLevelChild->title ?></a></li> <?php endforeach; ?> </ul> </li> <?php endforeach; ?> </ul> ..which outputs: So I must have $pages->children called earlier on the page somewhere (probably in the main menu above my test one) which would cause the double home link. I think @BitPoet was right earlier about the pointer. This would also be why @kongondo and myself were getting different output. 2 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now