Jump to content

Nav render children only


Smirftsch
 Share

Recommended Posts

Ok, I am absolutely sure I am missing something simple again, I also read a few more or less similar topics here, yet I couldn't find an answer.

I am using pretty much the original function renderNavTree:

function renderNavTree($items, $maxDepth = 0, $fieldNames = '', $class = 'nav') {

	// if we were given a single Page rather than a group of them, we'll pretend they
	// gave us a group of them (a group/array of 1)
	if($items instanceof Page) $items = array($items);

	// $out is where we store the markup we are creating in this function
	$out = '';

	// cycle through all the items
	foreach($items as $item) {

	    $pageid = wire('page')->id;
		// markup for the list item...
		// if current item is the same as the page being viewed, add a "current" class to it
		$out .= $item->id == wire('page')->id ? "<li class='current'>" : "<li>";

		// markup for the link
		$out .= "<a href='$item->url'>$item->title.$item->id.$pageid</a> ";

		// if there are extra field names specified, render markup for each one in a <div>
		// having a class name the same as the field name
		if($fieldNames) foreach(explode(' ', $fieldNames) as $fieldName) {
			$value = $item->get($fieldName);
			if($value) $out .= " <div class='$fieldName'>$value</div>";
		}

		// if the item has children and we're allowed to output tree navigation (maxDepth)
		// then call this same function again for the item's children 
        if($item->hasChildren() && $maxDepth ) {
			if($class == 'nav') 
                $class = 'nav nav-tree';
            if ($maxDepth > 1 || $item->id == wire('page')->id)
    				$out .= renderNavTree($item->children, $maxDepth-1, $fieldNames, $class);
    			else {
    				foreach($item->children as $childitem) {
    				if ($childitem->id == wire('page')->id)
    					$out .= renderNavTree($item->children, $maxDepth-1, $fieldNames, $class);
    				}
    			}
		}

		// close the list item
		$out .= "</li>";
	}

	// if output was generated above, wrap it in a <ul>
	if($out) $out = "<ul class='$class'>$out</ul>\n";

	// return the markup we generated above
	return $out;
}

 

but I want it only to render the children of the selected page.

Right now the output is like that (having lets say "child2 of child1 selected):

Parent Page

  • Parent
    • child 1
      • child of child 1
      • child2 of child 1
        • child of child2

Fine so far and looks as wanted- BUT - problem appears if having more than one child of parent- it looks like this:

  • Parent
    • child 1
      • child of child 1
      • child2 of child 1
        • child of child2 of child 1
    • child 2
      • child of child2
      • child2 of child2

while I only would want it to render the tree of child 1, not of child2.

Since all are children of Parent (hence same wire('page')->id), I can't distinguish it with id, but what else can I do here?

Ok, I realized that this question is maybe confusing, what I wanted to archive is that only the navtree of the selected page is being rendered, nothing else (well if being absolutely perfect maybe 1 level of rootParent also).

Link to comment
Share on other sites

for anyone digging such a thing, I mostly solved it now by using "renderNavTree($page.." instead of "renderNavTree($page->rootParent..." in basic-page and using parents() additionally:

 

// cycle through all the items
	foreach($items as $item) {
	
		if (renderParent && $item->id == wire('page')->id)
		{		
			$SkipLevel = 1; // Skip homepageroot 
			foreach($item->parents() as $pitem) 
			{					
				if ($SkipLevel)
				{
					$SkipLevel--;
					continue;	
				}
				$out .="<ul><li class='parentnav'><a href='$pitem->url'>$pitem->title</a></li>";
			}
			$out .="<ul>";
		}
...

only need to make it render 1st level of parentRoot yet 🙂

Link to comment
Share on other sites

If you haven't discovered it already, the parent() function (https://processwire.com/api/ref/page/parent/) used with a selector can be useful for checking if a page has a particular parent - at any level, not just a parent immediately above it. It returns a null page (id = 0) if the page doesn't have a parent that matches the selector.

For example, if you want to check if a page is a child of a page with id = 123:

if ($page->parent("id=123")->id != 0) {...

With other functions, the has_parent selector can be used for similar purposes.

Link to comment
Share on other sites

  • 5 months later...
On 1/24/2021 at 11:03 AM, Smirftsch said:
// if the item has children and we're allowed to output tree navigation (maxDepth)
		// then call this same function again for the item's children 
        if($item->hasChildren() && $maxDepth ) {
			if($class == 'nav') 
                $class = 'nav nav-tree';
            if ($maxDepth > 1 || $item->id == wire('page')->id)
    				$out .= renderNavTree($item->children, $maxDepth-1, $fieldNames, $class);
    			else {
    				foreach($item->children as $childitem) {
    				if ($childitem->id == wire('page')->id)
    					$out .= renderNavTree($item->children, $maxDepth-1, $fieldNames, $class);
    				}
    			}
		}

Same problem here: render submenus only for the current page.

Instead of Smirftsch's above, I tried the following (I have a non-$out-versionn of the RenderNavTree):

// if the item has children and we're allowed to output tree navigation (maxDepth)
		// then call this same function again for the item's children
		
		$currentItem = $item->id == wire('page')->id; 
		if(($item == $currentItem and $item->hasChildren())) {
			renderNavTree($item->children); 

and I call the function like so:

<aside id='sidebar'><?php
	
		// rootParent is the parent page closest to the homepage
		// you can think of this as the "section" that the user is in
		// so we'll assign it to a $section variable for clarity
// instead of $section, render the whole tree, beginning from the homepage
		$home = $pages->get('/'); 
	
		// if there's more than 1 page in this section...
		if($home->hasChildren > 1) {
			// output sidebar navigation
			// see _init.php for the renderNavTree function
			renderNavTree($home, $maxDepth = 2);
		}
	
		// output sidebar text if the page has it
		echo $page->sidebar; 
	
	?></aside><!-- end sidebar -->

only renders "Home" 😒 (I'm a non-coder anyway...)

image.thumb.png.b0f2c978ea7028ea842f88bec42861de.png

Link to comment
Share on other sites

found the code! In a post from 2011 😉 thx to @BDH

Does exactly what I want: show the whole tree, but only render submenus of a current item.

Could have achieved that with css also, but semantically, not that clean.

Now I tried to prepend the homepage like this (before the "foreach"), but doesn't work:

$rootPage->children->prepend($rootpage);

What am I doing wrong?

Anyway, I don't understand the $s=str_replace thing - works, but as I'm trying to learn from examples, would be nice to understand what that is.

There are still two modules: MarkupMenu and Menu Builder - but they seem to be overloaded for this simple task?

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