We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 15987
    • 786 Posts
    This is an auto-generated support/comment thread for Wayfinder.

    Use this forum to post any comments about this addition or any questions you have regarding its use.


    I am locking this thread, as it is geting way to long. If you have comment, question or request please create a new topic in the Wayfinder board.

    http://modxcms.com/forums/index.php/board,182.0.html
      • 11975
      • 2,542 Posts
      Hi,

      Looks pretty cool.

      Not yet tested but after having a look at parameters and code, it seems that we cannot access to TV.
      With DropMenu I had been able to add this features to make menu with image replacement technic.

      Do you plan to add this in future version ?

      Anyway, congratulations for this new version.

        Made with MODx : [url=http://www.copadel.com]copadel, fruits et l
        • 15987
        • 786 Posts
        heliotrope,
        can you point me in the direction of your modification of dropmenu for tvs? I will look into adding it, I’m just not sure what the functionality should be...
          • 11975
          • 2,542 Posts
          kylej,

          the idea is to be able to add a custom class or id to menu item according a TV(text).
          The main issue is that we have to avoid css conflict between ID (if the menu is called twice in the same document for instance to work on the same tree level) so we will use class.

          Well as I cannot explain as I’d like to, here is your code modified for this feature.
          As I am not a developper I don’t know if it’s the best way to do.

          The main changes are
          - I’ve added a parameter to the wf class (customCss) which is the name of The TV from which the values are retrieved
          - In the buidMenu function added in the $resource loop a call to getTemplateVar
          - Added a parameter to setItemClass function

          todo:
          -debug mode

          I guess that’s all.

          [[WayFinder? &customCss=`IdCssMenu` ]]


          <?php
          
          /*
           Snippet name: Wayfinder
           Short Desc: builds site navigation
           Version: beta
           Authors: Ryan Thrash (vertexworks.com)
                    Kyle Jaebker (muddydogpaws.com)
          */
          
          class Wayfinder {
              var $id = 0;
              var $level = 0;
              var $ph = FALSE;
              var $debug;
              var $ignoreHidden = FALSE;
              var $hideSubMenus = FALSE;
              var $textOfLinks = 'menutitle';
              var $titleOfLinks = 'pagetitle';
              var $templates = array();
              var $parentTree = array();
              var $wfDocs = array();
              var $css = array();
              var $cssTpl = FALSE;
              var $jsTpl = FALSE;
              var $rowPlaceHolders = array('[+wf.link+]','[+wf.title+]','[+wf.linktext+]','[+wf.wrapper+]','[+wf.classes+]');
              var $outerPlaceHolders = array('[+wf.wrapper+]','[+wf.classes+]');
              var $ie = "\n";
              var $customCss;//hack customCss which TV do  we have to look at
              var $debugOutput = '<h2>WayFinder Debug Output:</h2>';
          
              //remove any docs specified with hidemenu
              function filterHidden($var) {
          		return (!$var['hidemenu']==1);
          	}
          	
          	function endKey(&$array){
                  end($array);
                  return key($array);
              }
          
              //generate the menu
              function buildMenu($parentId,$curLevel = 1) {
                  global $modx;
                  $output = '';
          
                  $getFields = 'id,menutitle,pagetitle,menuindex,published,hidemenu,parent,isfolder,description,alias,longtitle';
                  $resource = $modx->getActiveChildren($parentId,'menuindex','ASC',$getFields);
          
                  if (!$this->ignoreHidden) {
                      $resource = array_filter($resource, array($this, "filterHidden"));
                  }
          
                  $firstItem = 1;
          
                  if (is_array($resource) && !empty($resource)) {
                      $numItems = $this->endKey($resource);
                      foreach ($resource as $n => $v) {
                          $v['link'] = $modx->makeUrl($v['id']);
                          $v['level'] = $curLevel;
                          $v['first'] = $firstItem;
                          //hack for specific css
                          if(!empty($this->customCss)){//
                          $mycss = $modx->getTemplateVar($this->customCss,$fields='id',$v['id']);
                          //print_r($mycss);
                          	if(!empty($mycss['value'])) {
                          	$v['specific'] = $mycss['value'];
                          	}
                          }
                          //endhack
                          $firstItem = 0;
                          if ($n == $numItems) {
                              $v['last'] = 1;
                          } else {
                              $v['last'] = 0;
                          }
          
                          $useTextField = (empty($v[$this->textOfLinks])) ? 'pagetitle' : "$this->textOfLinks";
                          $v['linktext'] = $v[$useTextField];
                          $v['title'] = $v[$this->titleOfLinks];
          
                          if ($v['isfolder'] && ($curLevel < $this->level || $this->level == 0) && (!$this->hideSubMenus || in_array($v['id'],$this->parentTree))) {
                              $oldLevel = $curLevel;
                              $subMenu = $this->ie . $this->buildMenu($v['id'],++$curLevel) . $this->ie;
                              $curLevel = $oldLevel;
                          } else {
                              $subMenu = '';
                          }
                          $output .= $this->renderRow($v,$subMenu);
                      }
          
                      if (!empty($this->templates['innerTpl']) && $curLevel > 1) {
                          $useChunk = $this->templates['innerTpl'];
                          $usedTemplate = 'innerTpl';
                      } else {
                          $useChunk = $this->templates['outerTpl'];
                          $usedTemplate = 'outerTpl';
                      }
          
                      if ($curLevel > 1) {
                          $wrapperClass = 'innercls';
                      } else {
                          $wrapperClass = 'outercls';
                      }
          
                      $useClass = $this->setItemClass($wrapperClass);
                      $phArray = array($output,$useClass);
          
                      $output = str_replace($this->outerPlaceHolders,$phArray,$useChunk);
          
                      if ($this->debug) {
                          $numDocs = $numItems + 1;
                          $this->debugOutput .= '<strong>Nesting Complete</strong> - Previous ' . $numDocs . ' level ' . $curLevel . ' items inserted into ' . $usedTemplate . ' with class ' . $useClass . '<br/>';
                      }
                  }
          
                  return $output;
              }
          
              //render each rows output
              function renderRow(&$resource,$subMenu) {
                  global $modx;
                  $output = '';
          
                  if ($resource['isfolder'] && !empty($this->templates['parentRowTpl'])) {
                      $usedTemplate = 'parentRowTpl';
                  } elseif ($resource['id'] == $modx->documentObject['id'] && !empty($this->templates['innerHereTpl']) && $resource['level'] > 1) {
                      $usedTemplate = 'innerHereTpl';
                  } elseif ($resource['id'] == $modx->documentObject['id'] && !empty($this->templates['hereTpl'])) {
                      $usedTemplate = 'hereTpl';
                  } elseif ($resource['level'] > 1 && !empty($this->templates['innerRowTpl'])) {
                      $usedTemplate = 'innerRowTpl';
                  } else {
                      $usedTemplate = 'rowTpl';
                  }
                  
                  $useChunk = $this->templates[$usedTemplate];
          
                  $useSub = $subMenu;
                  $useClass = $this->setItemClass('rowcls',$resource['id'],$resource['first'],$resource['last'],$resource['level'],$resource['isfolder'],$resource['specific']);
          
                  $phArray = array($resource['link'],$resource['title'],$resource['linktext'],$useSub,$useClass);
          
                  $output .= str_replace($this->rowPlaceHolders,$phArray,$useChunk);
          
                  if ($this->debug) {
                      $this->debugOutput .= '<strong>Item Processed: (' . $resource['id'] . ') ' . $resource['pagetitle'] . '</strong><br/>
                      template: ' . $usedTemplate . ' | class: ' . $useClass . '<br/>
                      level: ' . $resource['level'] . ' | First/Last: ' . $resource['first'] . '/' . $resource['last'] . '<br/>';
                  }
          
                  return $output . $this->ie;
              }
          
              //debugging to check for valid chunks
              function checkChunks() {
                  global $modx;
          
                  foreach ($this->templates as $n => $v) {
                      $chunkcheck = $modx->getChunk($v);
                      if (empty($v) || !$chunkcheck) {
                          if ($n === 'outerTpl') {
                              $this->templates[$n] = '<ul[+wf.classes+]>[+wf.wrapper+]</ul>';
                          } elseif ($n === 'rowTpl') {
                              $this->templates[$n] = '<li[+wf.classes+]><a href="[+wf.link+]" title="[+wf.title+]">[+wf.linktext+]</a>[+wf.wrapper+]</li>';
                          } else {
                              $this->templates[$n] = '';
                          }
                          if ($this->debug) {
                              $this->debugOutput .= '<p>No chunk found for <strong>' . $n . '</strong> using default.</p>';
                          }
                      } else {
                          $this->templates[$n] = $chunkcheck;
                      }
                  }
              }
          
              //determine "you are here"
              function isHere($did) {
                  return in_array($did,$this->parentTree);
              }
          
              //determine style class for current item being processed
              
              //added 1param to the function for customCss hack
              function setItemClass($classType, $docId = 0, $first = 0, $last = 0, $level = 0, $isFolder = 0, $specificCss ='') {
                  global $modx;
                  $returnClass = '';
                  $hasClass = 0;
          
                  if ($classType === 'outercls' && !empty($this->css['outer'])) {
                      //Set outer class if specified
                      $returnClass .= $this->css['outer'];
                      $hasClass = 1;
                  } elseif ($classType === 'innercls' && !empty($this->css['inner'])) {
                      //Set inner class if specified
                      $returnClass .= $this->css['inner'];
                      $hasClass = 1;
                  } elseif ($classType === 'rowcls') {
                      //Set row class if specified
                      if (!empty($this->css['row'])) {
                          $returnClass .= $this->css['row'];
                          $hasClass = 1;
                      }
                      //Set first class if specified
                      if ($first && !empty($this->css['first'])) {
                          $returnClass .= $hasClass ? ' ' . $this->css['first'] : $this->css['first'];
                          $hasClass = 1;
                      }
                      //Set last class if specified
                      if ($last && !empty($this->css['last'])) {
                          $returnClass .= $hasClass ? ' ' . $this->css['last'] : $this->css['last'];
                          $hasClass = 1;
                      }
                      //Set level class if specified
                      if (!empty($this->css['level'])) {
                          $returnClass .= $hasClass ? ' ' . $this->css['level'] . $level : $this->css['level'] . $level;
                          $hasClass = 1;
                      }
                      //Set parentFolder class if specified
                      if ($isFolder && !empty($this->css['parent']) && $level < $this->level) {
                          $returnClass .= $hasClass ? ' ' . $this->css['parent'] : $this->css['parent'];
                          $hasClass = 1;
                      }
                      //Set here class if specified
                      if (!empty($this->css['here']) && $this->isHere($docId)) {
                          $returnClass .= $hasClass ? ' ' . $this->css['here'] : $this->css['here'];
                          $hasClass = 1;
                      }
                      //hack customCss
                      //Set specific class if exists
                      if (!empty($specificCss)) {
                          $returnClass .= $hasClass ? ' ' . $specificCss : $specificCss;
                          $hasClass = 1;
                      }
                  }
          
                  if ($hasClass) {
                      $returnClass = ' class="' . $returnClass . '"';
                  }
                  return $returnClass;
              }
              
              //Add the specified css & javascript chunks to the page
              function regJsCss() {
                  global $modx;
                  
                  if ($this->debug) {
                      $this->debugOutput .= '<h3>Processing Css/Js Chunks</h3>';
                  }
                  
                  if ($this->cssTpl) {
                      $cssChunk = $modx->getChunk($this->cssTpl);
                      if ($cssChunk) {
                          $modx->regClientCSS($cssChunk);
                          if ($this->debug) {$this->debugOutput .= '<p>The CSS chunk ' . $this->cssTpl . ' was added to the page.</p>';}
                      } else {
                          if ($this->debug) {$this->debugOutput .= '<p>The CSS chunk ' . $this->cssTpl . ' was not found.</p>';}
                      }
                  }
                  
                  if ($this->jsTpl) {
                      $jsChunk = $modx->getChunk($this->jsTpl);
                      if ($jsChunk) {
                          $modx->regClientStartupScript($jsChunk);
                          if ($this->debug) {$this->debugOutput .= '<p>The JS chunk ' . $this->jsTpl . ' was added to the page.</p>';}
                      } else {
                          if ($this->debug) {$this->debugOutput .= '<p>The JS chunk ' . $this->jsTpl . ' was not found.</p>';}
                      }
                  }
              }
              
              function ultimateParent($id,$top) {
                  // From UltimateParent - snippet for MODx 0.9x
                  // March 2006 - [email protected]
                  global $modx;
                  if($id==$top || $id==0) { return $id; }
                  $pid = $modx->getParent($id,1,'id');
                  if($pid['id'] == $top) { return $id; }
                  while ($pid['id'] != $top && $pid['id'] != "") {
                      $id = $pid['id'];
                      $pid = $modx->getParent($id,1,'id');
                      if($pid['id'] == $top) { return $id; }
                  }
                  return 0; // if all else fails
              }
          }
          ?>
          


          The snippet

          <?php
          /*
          ::::::::::::::::::::::::::::::::::::::::
           Snippet name: Wayfinder
           Short Desc: builds site navigation
           Version: beta
           Authors: Ryan Thrash (vertexworks.com)
                    Kyle Jaebker (muddydogpaws.com)
           Date: August 2, 2006
          
           Changelog:
              August 2, 2006 - Initial Public Beta released
          ::::::::::::::::::::::::::::::::::::::::
          Description:
              Totally refactored from original DropMenu nav builder to make it easier to
              create custom navigation by using chunks as output templates. By using templates,
              many of the paramaters are no longer needed for flexible output including tables,
              unordered- or ordered-lists (ULs or OLs), definition lists (DLs) or in any other
              format you desire.
          ::::::::::::::::::::::::::::::::::::::::
          Example Usage:
              [[Wayfinder? &startId=`0`]]
          ::::::::::::::::::::::::::::::::::::::::
          */
          
          include_once("assets/snippets/wayfinder/wayfinder.inc.php");
          
          if (class_exists('Wayfinder')) {
             $wf = new Wayfinder();
          } else {
                  return 'error: Wayfinder class not found';
          }
          
          //parameter overrides
          if (isset($startUltimateParent)) {
              $topDoc = isset($topDoc)? $topDoc: 0;
              $wf->id = $wf->ultimateParent($modx->documentIdentifier,$topDoc);
          } else {
              $wf->id = isset($startId)? $startId: $modx->documentIdentifier;
          }
          $wf->level = isset($level)? $level: 0;
          $wf->ph = isset($ph)? $ph: FALSE;
          $wf->debug = isset($debug)? TRUE: FALSE;
          $wf->ignoreHidden = isset($ignoreHidden)? $ignoreHidden: FALSE;
          $wf->hideSubMenus = isset($hideSubMenus)? $hideSubMenus: FALSE;
          isset($removeNewLines)? $wf->ie = '': $wf->ie = "\n";
          //Include javascript & css chunks
          $wf->cssTpl = isset($cssTpl)? $cssTpl : FALSE;
          $wf->jsTpl = isset($jsTpl)? $jsTpl : FALSE;
          //get user class definitions
          $wf->css['first'] = isset($firstClass)? $firstClass: '';
          $wf->css['last'] = isset($lastClass)? $lastClass: 'last';
          $wf->css['here'] = isset($hereClass)? $hereClass: 'active';
          $wf->css['parent'] = isset($parentClass)? $parentClass: '';
          $wf->css['row'] = isset($rowClass)? $rowClass: '';
          $wf->css['outer'] = isset($outerClass)? $outerClass: '';
          $wf->css['inner'] = isset($innerClass)? $innerClass: '';
          $wf->css['level'] = isset($levelClass)? $levelClass: '';
          
          //hack to add custom css 
          //specify the name of TV from which we get the values
          $wf->customCss = isset($customCss) ? "$customCss" : '';
          
          //get fields to output
          $wf->textOfLinks = (isset($textOfLinks)) ? $textOfLinks : 'menutitle';
          $wf->titleOfLinks = (isset($titleOfLinks)) ? $titleOfLinks : 'pagetitle';
          //get user templates
          $wf->templates['outerTpl'] = isset($outerTpl) ? $outerTpl : '';
          $wf->templates['rowTpl'] = isset($rowTpl) ? $rowTpl : '';
          $wf->templates['parentRowTpl'] = isset($parentRowTpl) ? $parentRowTpl : '';
          $wf->templates['hereTpl'] = isset($hereTpl) ? $hereTpl : '';
          $wf->templates['innerTpl'] = isset($innerTpl) ? $innerTpl : '';
          $wf->templates['innerRowTpl'] = isset($innerRowTpl) ? $innerRowTpl : '';
          $wf->templates['innerHereTpl'] = isset($innerHereTpl) ? $innerHereTpl : '';
          //setup here checking array
          $wf->parentTree = $modx->getParentIds($modx->documentIdentifier);
          $wf->parentTree[] = $modx->documentIdentifier;
          
          if ($wf->debug) {
              $wf->debugOutput .= '<p>Starting Menu from Docid: ' . $wf->id . '<br/>';
              $wf->debugOutput .= 'Docids for \'Here\' class checking: ' . implode(', ',$wf->parentTree) . '</p>';
              $wf->debugOutput .= '<h3>Chunk Checks</h3>';
          }
          
          $wf->checkChunks();
          
          if ($wf->cssTpl || $wf->jsTpl) {
              $wf->regJsCss();
          }
          
          if ($wf->debug) {
              $wf->debugOutput .= '<h3>Document Processing</h3>';
          }
          
          $output = $wf->buildMenu($wf->id);
          
          if ($wf->debug) {
              $output = $output . $wf->debugOutput;
          }
          
          if ($ph) {
              $modx->setPlaceholder($ph,$output);
          } else {
              return $output;
          }
          


          :-)


            Made with MODx : [url=http://www.copadel.com]copadel, fruits et l
            • 11975
            • 2,542 Posts
            Sorry for the approximative english in the previous post, I just woke up.
            Hope that make sense.

            I keep on testing and can’t get the topdoc to work.

            here is a screenshot of my tree repository



            the snippet call:
            [!WayFinder? &startUltimateParent=true   &topDoc=`56` !]

            and the result:



            As you can see, it brings back all the docs contained in the tree repository and not the content from folder 56

            I’m not sure of the aim of topDoc since I can produce the same effect with startId=56

            Perhaps I misunderstood something.

            :-)


            EDIT: about the code posted above, I was thinking that we could achieve the same result by adding to each item a css id made with its id prefixed with doc. The only reason I prefered using TV is for css reading and coding.
              Made with MODx : [url=http://www.copadel.com]copadel, fruits et l
              • 28338
              • 46 Posts
              Hi!

              I have called WayFinder with both a &parentRowTpl and a &parentClass, but none of them seem to have any effect. Is the parent-features a work in progress or am I out of luck?

              I believe WayFinder will be _really_ nice when it’s done. Can’t wait to start rebuilding the menus of my sites smiley

              Update: The &parentRowTpl works, but the &parentClass does still not appear.
                • 15987
                • 786 Posts
                @heliotrope - thanks for the code update. I will give it a look over and see about integrating it into the main snippet.

                Here is how the startUltimateParent & topDoc are supposed to work. If you call it like your example, when you are on a page inside of folder 56 you will see a menu that shows all items under doc folder 56. If you are not in folder 56 it will start from the site root 0. It acts this way because the currentdocId and the topdoc is passed to the ultimateparent function (same as the snippet). So if you are inside folder 56 ultimateparent will go up the tree until it hits 56 to find where to start the menu from. If you are not inside folder 56 it will go up the tree all the way to 0 because it will never find doc 56.

                I hope that makes sense, let me know if it is not functioning this way for you.



                @staed - &parentClass only gets set if the following conditions are met:

                the item is a folder, a class was specified in the snippet call, and the level of the item is less than the &level parameter.

                So if you have a folder and your menu is displaying the items underneath it it should get the class.

                If that doesn’t clear it up post your snippet call and the parentRowTpl chunk and I will help fix the problem. Also a screen shot of your manager tree would help as well.
                  • 28338
                  • 46 Posts
                  I had &level=`0` (infinite), but then I changed that to 6 and then it worked great! I bet that is a bug and not a feature smiley

                  Everything should be considered lower than 0, right?
                    • 15987
                    • 786 Posts
                    Can you try taking out the level parameter and see if you get the same result. Setting it to 0 should get you the full menu tree, it defaults to 0 also. So you really shouldn’t need to set it in the snippet call.
                      • 28338
                      • 46 Posts
                      I had it unspecified before I tried with a specific number, and after I specified `0` with the same result as when it was using the default value.

                      This discussion is closed to further replies. Keep calm and carry on.