We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 36635
    • 41 Posts
    Hi, does anyone have a snippet that gets all children of a document including all descendants?

    Just looking to save a little coding...
    thanks much
      • 25663 MODX Staff
      • 12,272 Posts
      What is this for and what would you like it to do? You can look at pretty much any menu building snippet for code examples.
        Ryan Thrash, MODX Co-Founder
        Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
        • 22303 MODX Staff
        • 10,725 Posts
        You can get all of a docs children id’s with $modx->getChildIds($id), then pass that list as an IN clause to $modx->getDocuments()...
          • 36635
          • 41 Posts
          Thanks for getting back. I have a hierarchy several levels deep under a node on the document tree. I need to allow editors to multi-select any node on this tree. Many children or parents may be relevant to the current document.

          So I made this snippet to walk the tree and built a TV input bind. Select works good. I still need to work on the display because it wrongly highlights the entire tree (using multi-select list).

          Here’s the snippet code that works to fill the TV in the editor using:
          @eval return $modx->runSnippet(’SelectMovements’,array(’docid’=>2));

          Is there any easier way?
          thanks,
          ---todd


          
          	// Walk Tree of All Descendants
          	
          	// Used to build multi-select list of hierarchy for selecting a template variable
          	
          	$ic = 0;
          	$depth = array();
          	$idepth = 0;
          	$c = array();
          	$bDone = false;
          	$o = '';
          
          	// parameter: &docid=root document of tree
          	if (!$docid) { return ''; }
          	
          	// do we just build array
          	// or process and not leave tracks?
          
          	// $c array is children id's and values ($ic is index)
          	// $depth array is index to current level item while we're traversing ($idepth is index)
          	// 		used for backtracking
          	$c[$idepth] = array( array("id" => $docid, "pagetitle" => "root") );
          	$depth[$idepth] = 0;
          	
          	while (!$bDone)	{
          		$thisid = $c[$idepth][$ic]["id"];
          		$pg = $c[$idepth][$ic]["pagetitle"];
          		
          		if ($thisid != $docid)	{		// don't process root node
          			// process this node
          			for ($i=1; $i<$idepth; $i++)	{
          				$o .= "-";
          			}
          			$o .= "$pg==$this||";
          		}
          		
          		$a = $modx->getDocumentChildren($thisid,1,0,'id,pagetitle');
          		if ($a)	{
          			// yes children, descend
          			$depth[$idepth] = $ic;		// hold current position for continuing
          			$idepth++;					// down one
          			$c[$idepth] = $a;			// store this level's siblings
          			$ic=0;						// start at first child
          			$depth[$idepth] = $ic;		// current level's position
          		}
          		else	{
          			$ic++;	// next sib
          		}
          		
          		while (!$bDone && $idepth && !isset($c[$idepth][$ic]))	{
          			// no element here, go up
          			$idepth--;
          			if ($idepth)	{
          				$ic = $depth[$idepth];		// last parent
          				$ic++;						// next sib
          			}
          			else	{
          				$bDone = true;
          			}
          		}
          	}
          	return $o;
          
          

            • 36635
            • 41 Posts
            Just in case someone needs this too, just found why the multi-select didn’t work:

            change:
            $o .= "$pg==$this||";
            to
            $o .= "$pg==$thisid||";

            Now the multi-select list shows a hierarchy and the editor/user can multi-select any item in a Template Variable.

            I just used dashes to indicate children in the list.
              • 22303 MODX Staff
              • 10,725 Posts
              Quote from: avibodha at Aug 24, 2006, 06:13 PM

              Is there any easier way?

              Yes, well, maybe not easier, but better I think. Anyway, there is a map available as $modx->documentMap, which is an array of parent document id values keyed for every document in the system. The $modx->getChildIds() function uses this map to build a flat list of all children without any queries to the database, but you could just as easily use the map to create your tree structure ahead of time, then you can issue a single query (rather than looping through and issuing multiple queries, one for each node) as I suggested earlier, to populate a multi-dimensional array of the results.

              In SVN, and the upcoming release, getChildIds() can be called with a second depth parameter that can be used to retrieve a node at a time, if you find it that approach more to your liking.

              The key point I’m trying to make here is there is no need to query in order to find the children; you can use the $modx->documentMap, $modx->getChildIds() and/or $modx->getParentIds() to define your queries and result set structures any way you want to. I’ll make some more information on this available in the documentation of the API soon; including some sample code.
                • 36635
                • 41 Posts
                Thanks, yes that sounds great!