ProcessWire - Navigation Snippets: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
Zeile 90: Zeile 90:
 
?></div>
 
?></div>
 
</pre>
 
</pre>
 +
 +
=== Einfache One Level Navigation aus Page Array ===
 +
Für viele Zwecke nutzbar wenn kein Tree Menu erforderlich ist (also nur eine Ebene)
 +
 +
<syntaxhighligh lang="php">
 +
$out = "<ul class='topnav'>";
 +
foreach($homepage->and($homepage->children) as $item) { // homepage and its visible children
 +
  if($item->id == $page->rootParent->id) {
 +
    $out .= "<li class='current'>";
 +
  } else {
 +
    $out .= "<li>";
 +
}
 +
$out .= "<a href='$item->url'>$item->title</a></li>";
 +
$out .= "</ul>";
 +
</syntaxhighlight>
  
 
=== Main Level Navigation Bar ===
 
=== Main Level Navigation Bar ===

Version vom 27. Juni 2017, 08:57 Uhr

Basics

Page Level

In which level in page tree we are?

$level = count($page->parents);

Link to Subpage und Platzhalter (Spacer)

Kann man gut für Superfish Menüs etc. benutzen. Bildet das Verhalten von Shortcuts und Spacern aus TYPO3 nach.

Anpassung der renderNavTree() Funktion von Ryan Cramer. Options Field Installieren und als globales Feld "navigation_type" mit den Optionen

1=normal|Normal
2=doNotLink|Do not link
3=linkToFirstChild|Link to first childpage

konfigurieren. Dann Funktion etwa so anpassen:

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

		// 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
		$navigation_type = $item->navigation_type->id;
		switch ( $navigation_type ) {
			case 2: // do not link
				$out .= "<span class='spacer'>$item->title</span>";
				break;
			case 3: // link to subpage
				if( $item->hasChildren() ){
					$out .= '<a href="'.$item->child->url.'">'.$item->title.'</a>';
				}else{
					$out .= "<span class='spacer'>$item->title</span>";
				}
				break;
			default:
				$out .= "<a href='$item->url'>$item->title</a>";
				break;
		}
...

Redirect (301)

Redirect zu erster Unterseite

https://processwire.com/talk/topic/15-how-do-i-create-a-page-that-redirects-to-its-first-child/

Field redirects_to_first_child erstellen und im Template einfügen.

<?php 
  if($page->numChildren && $page->redirects_to_first_child) 
  $session->redirect($page->child()->url); 
?>

Erzeugt 301 Weiterleitung

Anderer Ansatz wäre evtl. den Link bei der Menügenerierung direkt zu generieren.

Redirect anderer Seite in der Navigation

https://processwire.com/talk/topic/762-howto-menu-item-that-links-to-another-page/

1. Create a new field and call it 'redirect_url' or something like that, and use the 'URL' fieldtype.

2. Add that field to your template where you'd want to use it, or create a new template just for the purpose, like a template named 'redirect'.

3. Edit the page that you want to be a symlink and populate the 'redirect_url' field with the URL you want it to redirect to.

4. In your nav-generation code that links to the pages, do something like this:

<?php
$url = $subpage->get("redirect_url|url"); // use redirect_url if there, otherwise use url
echo "<a href='$url'>{$subpage->title}</a>";

5. You might also want to add this to your template that has the 'redirect_url' field: just in case there's anything linking to it directly. That way it'll send people to the right place either way:

<?php
if($page->redirect_url) $session->redirect($page->redirect_url); 

Breadcrumb

	<!-- breadcrumbs -->
	<div class='breadcrumbs'><?php 
		// breadcrumbs are the current page's parents
		foreach($page->parents() as $item) {
			echo "<span><a href='$item->url'>$item->title</a></span> "; 
		}
		// optionally output the current page as the last item
		echo "<span>$page->title</span> "; 
	?></div>

Einfache One Level Navigation aus Page Array

Für viele Zwecke nutzbar wenn kein Tree Menu erforderlich ist (also nur eine Ebene)

<syntaxhighligh lang="php">

$out = "

    "; foreach($homepage->and($homepage->children) as $item) { // homepage and its visible children if($item->id == $page->rootParent->id) { $out .= "
  • "; } else { $out .= "
  • "; } $out .= "<a href='$item->url'>$item->title</a>
  • "; $out .= "

";

</syntaxhighlight>

Main Level Navigation Bar

Homepage + Kindseiten (1 Level). Die Variable $homepage wird i.d.R. in init.php definiert:

$homepage = $pages->get('/');
$out = "<ul class='topnav'>";
foreach($homepage->and($homepage->children) as $item) { // homepage and its visible children
  if($item->id == $page->rootParent->id) {
    $out .= "<li class='current'>";
  } else {
    $out .= "<li>";
}
$out .= "<a href='$item->url'>$item->title</a></li>";
$out .= "</ul>";

Nächste Seite / Next Page Navigation

if($page->next->id){
  $next = '
    <div class="next">
      <i>Next:</i>&nbsp;
      <a class="ajax-link" name="'.$page->next->title.'" href="'. $page->next->url .'">
        '. $page->next->title .'<span class="fa fa-arrow-right"><span>
      </a>
    </div>';
}

Zurück zur Elternseite

<div class="back"><a href="'.$page->parent()->url.'">zurück</a></div>

Kindseiten mit $page->children

<?=$page->children?>

Output

5723,4958,5937

Beispiel

<ul>
<?php
foreach($page->children as $child)
  echo "<li><a href='{$child->url}'>{$child->title}</a></li>";
?>
</ul>

Ergebnis:

<ul>

<li><a href='/about/contact/'>Contact Us</a></li>
<li><a href='/about/press/'>Press Releases</a></li>
<li><a href='/about/staff/'>Our Staff</a></li>

</ul>

Children Tree

function listChildrenTree($children, $current, $w) {

echo "<ul>";

foreach($children as $page) {

	$class = '';
	if($page === $current || $current->parents->slice(1)->has($page) ) {
		$class = "class='on' style='font-weight:bold'";
	}

	$rootid = $w->pages->get("/")->id;

	echo "<li><a href='{$page->url}' $class>";
	if($page->id == $rootid) echo "<img src='" . $w->config->urls->templates . "styles/images/home.png' width='24' height='28' alt='' />";
	echo "{$page->title}</a> ";

	if($page->numChildren && $page->id != $rootid) listChildrenTree($page->children, $current, $w);

	echo "</li>";
}
echo "</ul>";
}

$children = $pages->get("/")->children();
$children->prepend($pages->get("/"));

listChildrenTree($children, $page, $wire);

Bootstrap Navigation

<?php namespace ProcessWire;
// Markup to use wicht navigation_type field (normal=1, no-link=2,subpage=3)
?>

<?php

// bundle up the first level pages and prepend the root home page
$homepage = $pages->get(1);
$pa = $homepage->children;
$pa = $pa->prepend($homepage);

// Set the ball rolling...
$myMenu = renderChildrenOf($pa);
$wrapper = '
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Menü</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
    </div>
    <div class="collapse navbar-collapse" id="navbar-collapse-1">
      |
    </div>
  </div>
</div>';
$myMenu = wrap($myMenu,$wrapper);
echo $myMenu;
/*
Navigation for ProcessWire using the Bootstrap 2.2.2 markup
This menu was written by Soma based on work by NetCarver and a bit thrown in by Joss

Navigation Bootstrap 3 update by Damienov, with multi level dropdown support fix
*/

function renderChildrenOf($pa, $output = '', $level = 0)
{
    $output = '';
    $level++;

    foreach ($pa as $child) {
        $atoggle = '';
        $class = '';

        if ($child->numChildren && count($child->parents) == 1) {
            $class .= 'dropdown';
            $atoggle .= ' class="dropdown-toggle" data-toggle="dropdown"';
        } else if ($child->numChildren && count($child->parents) > 1 ) {
            $class .= 'dropdown-submenu';
            $atoggle .= ' class="dropdown-toggle"';
        } else if ($child->numChildren && $child->id != 1) {
            $class .= 'dropdown-menu';
        }

        // Makes the current page and it's top level parent add an active class
        $class .= ($child === wire("page") || $child === wire("page")->rootParent) ? " active" : '';
        $class = strlen($class) ? " class='" . trim($class) . "'" : '';

        if ($child->numChildren && count($child->parents) == 1) {
            // Add Caret if have children
            $output .= "<li$class><a href='$child->url'$atoggle>$child->title <b class='caret'></b></a>";
        } else if ($child->numChildren && count($child->parents) > 1) {
            $output .= "<li$class><a tabindex='-1' href='$child->url'$atoggle>$child->title</a>";
        } else {
            $output .= "<li$class><a href='$child->url'$atoggle>$child->title</a>";
        }

        // If this child is itself a parent and not the root page, then render it's children in their own menu too...
        if ($child->numChildren && $child->id != 1) {
            $output .= renderChildrenOf($child->children, $output, $level);
        }
        $output .= '</li>';
    }
    $outerclass = ($level == 1) ? "nav navbar-nav" : 'dropdown-menu';
    return "<ul class='$outerclass'>$output</ul>";
}

?>

MarkupSimpleNavigation

Processwire Modul - MarkupSimpleNavigation

Weitere Menüs

Menüauswahl Hauptmenü / Metamenü / Footer-Navigation

Beispiel 1 Backend Feld menus anlegen Options:

1=Main Menu
2=Meta Menu 

topnav.inc

$pa = $homepage->and($homepage->children("menus.id=1"));//only if main menu is checked
$options = array('level' => '1', 'ulClass' => 'sf-menu', 'liClass' => '');
echo "<div>".renderNavTreeType($pa, $maxDepth = 1, $fieldNames = '', $options)."</div>";


Beispiel 2 (älter)

Checkbox anlegen (footer_nav), und dann das Seitenarray etwa so modifizieren.

$footer_nav = $pages->find("parent=1, footer_checkbox=1");
$main_nav = $pages->find("parent=1, footer_checkbox!=1");

Zweispaltige Navigation aus Kindseiten

Verbesserungsvorschlag: Anstatt if lieber zwei for Schleifen -> bessere Performance

// Childrens
$n = count($page->children);
$m = ceil($n/2);
$c = 0;

// NAVIGATION & SLIDER Items
$listItem = '';
$navList = '';
$col1 = '<ul class="nav-list col1">';
$col2 = '<ul class="nav-list col2">';
foreach ($page->children as $item) {
	if($item->id == $page->rootParent->id) {
		$listItem = '<li class="current">';
	} else {
		$listItem = '<li>';
	}
	$listItem .= '<a class="ajax-link" href="'.$item->url.'">'.$item->title.'</a></li>';
	($c < $m) ? $col1 .= $listItem : $col2 .= $listItem;
	$c++;
}
$col1 .= '</ul>';
$col1 .= '</ul>';
$navList = $col1.$col2;

Pushy Menu

/**
 * Given a group of pages, render a <ul> navigation tree
 *
 * This is here to demonstrate an example of a more intermediate level
 * shared function and usage is completely optional. This is very similar to
 * the renderNav() function above except that it can output more than one
 * level of navigation (recursively) and can include other fields in the output.
 * Assumes there is a field navigation_type to decide how a list item is
 * rendered
 *
 * @param array|PageArray $items
 * @param int $maxDepth How many levels of navigation below current should it go?
 * @param string $fieldNames Any extra field names to display (separate multiple fields with a space)
 * @param array $options extra options for classes configuration etc.
 * @return string
 *
 */
function renderPushyMenu($items, $maxDepth = 0, $fieldNames = '', $options = array('level' => 0, 'ulClass' => '', 'liClass' => '', 'aClass' => '') ) {

	// 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 = '';
  $c = 0;
  $liClasses = array();
  $ulClasses = array();
	$level = 0;
	$liClass = '';
	$ulClass = '';

	if(!empty($options['level'])) $level = $options['level'];
	if(!empty($options['ulClass'])) {
		$ulClasses[] = $options['ulClass'];
		$ulClass = $options['ulClass'];
	}

	if(!empty($options['liClass'])) {
		$liClasses[] = $options['liClass'];
		$liClass = $options['liClass'];
	}

	// cycle through all the items
	foreach($items as $item) {
    //$level = count($page->parents);
		// LI ITEM
		$classes = $liClasses;
    //if($item->id == wire('page')->id) $classes[] = 'cur';
		if($item->hasChildren) {
      // BUTTON instead of Link
      $out .= '<li class="pushy-submenu"><button>'.$item->title.'</button>';
		}else{
      $classes[] = 'level-'.$level;
  		$out .= '<li class="'.implode($classes,' ').'">';
      unset($classes);

  		// A ITEM
  		$navigation_type = $item->navigation_type->id;
  		$classes = $liClasses;
  		switch ( $navigation_type ) {
  			case 2: // do not link
  				$out .= '<span class="spacer">'.$item->title.'</span>';
  				break;
  			case 3: // link to subpage
  				if( $item->hasChildren() ){
  					$out .= '<a href="'.$item->child->url.'" class="ajax-link">'.$item->title.'</a>';
  				}else{
  					$out .= "<span class='spacer'>$item->title</span>";
  				}
  				break;
  			default:
  				$out .= '<a href="'.$item->url.'" class="ajax-link">'.$item->title.'</a>';
  				break;
  		}
  		unset($classes);
		}
		// 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';
			$nextLevelOptions = array('level' => $level+1, 'ulClass' => '', 'liClass' => $liClass);
			$out .= renderNavTreeType($item->children, $maxDepth-1, $fieldNames, $nextLevelOptions);
		}

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

	// if output was generated above, wrap it in a <ul>

	if($out) $out = "\n".'<ul class="'.implode($ulClasses,' ').'">'."\n".$out.'</ul>'."\n";

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

Do not link / link to subpage

Zusätzliches Feld (Options) im Backend mit Namen navigation_type

Beispiel

/**
 * Given a group of pages, render a <ul> navigation tree
 * If there is a field navigation_type the vals have following meaning
 * 1 = Normal
 * 2 = Do not link
 * 3 = Link to subpage
 *
 * @param array|PageArray $items
 * @param int $maxDepth How many levels of navigation below current should it go?
 * @param string $fieldNames Any extra field names to display (separate multiple fields with a space)
 * @param string $class CSS class name for containing <ul>
 * @return string
 *
 */
function renderNavTreeType($items, $maxDepth = 0, $fieldNames = '', $options = array('level' => 0, 'ulClass' => 'nav', 'liClass' => '', 'aClass' => '') ) {

	// 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 = '';
  $c = 0;
  $liClasses = array();
  $ulClasses = array();
	$level = 0;
	$liClass = '';
	$ulClass = '';

	if(!empty($options['level'])) $level = $options['level'];
	if(!empty($options['ulClass'])) {
		$ulClasses[] = $options['ulClass'];
		$ulClass = $options['ulClass'];
	}

	if(!empty($options['liClass'])) {
		$liClasses[] = $options['liClass'];
		$liClass = $options['liClass'];
	}

	// cycle through all the items
	foreach($items as $item) {
    //$level = count($page->parents);
		// LI ITEM
		$classes = $liClasses;
    if($item->id == wire('page')->id) $classes[] = 'cur';
		if($item->hasChildren) $classes[] = 'has_children';
    $classes[] = 'level-'.$level;
		$out .= '<li class="'.implode($classes,' ').'">';
    unset($classes);

		// markup for the link
		$navigation_type = $item->navigation_type->id;
		$classes = $liClasses;
		switch ( $navigation_type ) {
			case 2: // do not link
				$out .= '<span class="spacer">'.$item->title.'</span>';
				break;
			case 3: // link to subpage
				if( $item->hasChildren() ){
					$out .= '<a href="'.$item->child->url.'" class="ajax-link">'.$item->title.'</a>';
				}else{
					$out .= "<span class='spacer'>$item->title</span>";
				}
				break;
			default:
				$out .= '<a href="'.$item->url.'" class="ajax-link">'.$item->title.'</a>';
				break;
		}
		unset($classes);
		// 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';
			$nextLevelOptions = array('level' => $level+1, 'ulClass' => '', 'liClass' => $liClass);
			$out .= renderNavTreeType($item->children, $maxDepth-1, $fieldNames, $nextLevelOptions);
		}

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

	// if output was generated above, wrap it in a <ul>

	if($out) $out = "\n".'<ul class="'.implode($ulClasses,' ').'">'."\n".$out.'</ul>'."\n";

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