Jump to content

Can anyone tell me the difference between the following pieces of code


SamC
 Share

Recommended Posts

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

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

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

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. :-)

  • Like 1
Link to comment
Share on other sites

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 :P.

Link to comment
Share on other sites

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? :undecided:

Link to comment
Share on other sites

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

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

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

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 :P

I can't see any errors in the code, or any other code that would affect this throughout the site.

  • Like 1
Link to comment
Share on other sites

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.

  • Like 4
Link to comment
Share on other sites

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:

2018-01-24_085925.png.06a4e0c42c266b88f23a70babbb06404.png

Weird.

  • Like 1
Link to comment
Share on other sites

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! :lol: thanks @BitPoet

Link to comment
Share on other sites

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

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

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):

2018-01-24_135224.png.d7204c3e2ea0a184056b343d975e6a21.png

Edited by Robin S
corrected screenshot
  • Like 3
Link to comment
Share on other sites

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.

  • Like 4
Link to comment
Share on other sites

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:

testing_double_home.jpg

...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:

testing_single_home.jpg

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.

  • Like 2
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...