pdoNeighbors always links to root

Hi,

I have a problem with pdoNeighbors with custom templates:

[[!pdoNeighbors?
    &sortby=`menuindex`
    &sortdir=`asc`
    &loop=`0`
    &useWeblinkUrl=`1`
    &tplPrev=`@INLINE <div id="navigator_prev"><span class="link-prev"><a class="navlink_prev" rel="prev" type="text/html" href="/[[+uri]]"><< Zurück: [[+pagetitle]]</a></span></div>`
    &tplUp=`@INLINE <span class="link-up">&uarr; href="/[[+uri]]">[[+pagetitle]]</a></span>`
    &tplNext=`@INLINE <div id="navigator_next"><span class="link-next"><a class="navlink_next" rel="next" type="text/html" href="/[[+uri]]">Vorwärts: [[+pagetitle]] >></a></span></div>`
    &tplWrapper=`@INLINE <div class="neighbors">[[+prev]][[+next]]</div>`
]]

It results in html code where the parameter +uri is empty. I copied he template code from the docs for pdoNeighbors. If I call the snippet without templates it works. I tried +url because I assumed a typo, but that isn’t it.

Any clues?

Kind regards
Andre

Try using {{+uri}} instead of [[+uri]] in your inline templates.

The way the MODX parser works, inner tags are processed first. So the parser tries to replace all the tags in the @INLINE templates, before “pdoNeighbors” is even called.
When you use curly braces {{...}}, the tags are ignored by the MODX parser and get converted to normal MODX tags by “pdoNeighbors”.

Hi,
unfortunatly, this didn’t work. A lot of experimenting resultet in working links by using href="/[[+link]]" instead of href="/[[+uri]]"

But now I have another problem: pdoNeighbors logic gives me the neighbors according to their level. Thus, if I have:

Parent1
Child1a
Child1b
Parent2
Child2a
Child2b

I get Parent2 as the neighbor for Parent1. But for my prev/next links I would to have iteration through the document tree, descending from Parent1 over Child1a all the way down to Child2b.

Any clues how this could be achieved?

Kind regards
Andre

I believe you should be able to use the depth attribute to search down the tree - I’m not sure but it may require you to specify the id of the main parent [in this case, the parent of Parent1 & Parent2] - :

&id=`1234`
&depth=`2`

You wrote in your previous question, that you used the extra/snippet “navigator” for this.

I don’t know this extra/snippet and can’t find any reference to it. Is there maybe a (Github) page with the code somewhere?
Usually snippets of this kind still work correctly in MODX 3 (when they worked in MODX 2.x). So if you still have the code/transport-package somewhere, it might work when you use it in MODX 3.

To answer your last question first: I used navigator with modx 0.9.6.3. I would have to have access to the file system to copy code in. I tried to copy it in a new snippet, but this didn’t work.

To pdoneighbors:

My parents in the doc tree don’t have a parent, it’s just the one called “Website” (the default front-end context), but this doesn’t have an id. I could change to doc trees’ structure, but I don’t know if that interfers with my menues in wayfinder.

My snippet call is:

[[!pdoNeighbors?
    &id=`2`
    &depth=`2`   
    &sortby=`menuindex`
    &sortdir=`asc`
    &loop=`0`
    &tplPrev=`@INLINE <div id="navigator_prev"><span class="link-prev"><a class="navlink_prev" rel="prev" type="text/html" href="/[[+link]]"><< Zurück: [[+pagetitle]]</a></span></div>`
    &tplUp=`@INLINE <span class="link-up">&uarr; href="/{{+uri}}">[[+pagetitle]]</a></span>`
    &tplNext=`@INLINE <div id="navigator_next"><span class="link-next"><a class="navlink_next" rel="next" type="text/html" href="/[[+link]]">Vorwärts: [[+pagetitle]] >></a></span></div>`
    &tplWrapper=`@INLINE <div class="neighbors">[[+prev]][[+next]]</div>`
]]

id=2 is first parent. I tried id=0 as well, but this doesn’t work either. As I sort by menuindex ascending, I thought it should work, as the menuindes is ascending from top to buttom of the doc tree.

Any other ideas?

Or could it achieved by wayfinder, which I use for my menues?

Kind regards
Andre

I didn’t know your installation was that old.
It’s unsurprising that the snippet code doesn’t work anymore.


I don’t think you can achieve what you want with pdoNeighbors. pdoNeighbors gives you 3 results: The previous sibling, the next sibling and the parent.
But if your current resource is (for example) “Child1b”, there is no way to get “Parent2” (which is the next sibling of the parent).

I don’t think Wayfinder can be used for this either.

You could write a custom snippet to take care of most of this.

Your biggest issue though is going to be keeping your items in order.

Ordering by menuindex makes sense to a point - but if the list of resources will be growing then it will quickly become unmanageable since the resources span multiple levels of the resource tree.

I can’t think of any straightforward solution.

Can you share this code?
Maybe it can be adapted to work with MODX 3.

yes, I will post it after this post, hopefully it will not set automatically hidden by the spamfilter again

<?php
/*
===================================================================
Snippet: Navigator
===================================================================
Version: 0.1
Date: 2008.12.17
Author: PMS
Licence: GPL GNU - Public
Credit: I used some code from the Wayfinder snippet when figuring out how to do templating.

===================================================================
About:
===================================================================

This snippet is designed to aid navigation, by providing information about a related page.
Currently, the only relationships this snippet handles are: next, previous (prev) and parent (up)
The snippet uses templating, so you can display whatever information you want about the related pages,
but it's likely to be most useful just for creating links to them.
It's supposed to be an improvement on the PrevJumpNext snippet
in that it has the ability to transcend levels of the menu system.
It doesn't attempt to provide the 'Jump' facility of the PrevJumpNext snippet.

===================================================================
Installation
===================================================================

1. Copy the navigator folder into assets/snippets/
2. In modx, go to Resources->Manage Resources->Snippets.
3. Create a new snippet and enter the following details:
    Snippet Name: Navigator
    Description: <strong>0.1</strong> Enables navigation to related pages (prev, next, up)
4. Copy the contents of navigator.snippet.php into the Snippet Code box and save the snippet.

===================================================================
Usage:
===================================================================

To use this snippet you'll have to provide a template for the information you want
to display about the related page.
Within the template you can use:
* modx document variable placeholders [+id+], [+pagetitle+], [+description+], etc...
* template variable placeholders [+mytv+]
* Navigator placeholders

Currently, the only navigator placeholder available is  [+nav.rel+], which returns the relationship with
the document: 'next', 'prev', or 'up'. See the &rel input parameter.

===================================================================
Example templates and snippet calls:
===================================================================

Provide links to related pages using the link element:
LinkChunk: <link rel="[+nav.rel+]" type="[+contentType+]" href="[(site_url)][~[+id+]~]"></link>
[[Navigator? &rel=`prev` &template=`LinkChunk`]]
[[Navigator? &rel=`up` &template=`LinkChunk `]]
[[Navigator? &rel=`next` &template=`LinkChunk `]]

Provide links to related pages using a hyperlink:
PrevChunk: <a class="navlink" rel="[+nav.rel+]" type="[+contentType+]" href="[(site_url)][~[+id+]~]">Prev</a>
[[Navigator? &rel=`prev` &template=`PrevChunk `]]

======================================================
Configuration Settings
======================================================

&rel [string]
The relationship that the document to be found has to the current document:
'next', 'prev', 'up'
Default: 'up'

&stopIds [string]
A comma separated list of document ids.
If the id of the related document appears in this list, the empty string is returned.
This is useful for specifying starts and ends of sequences of documents
Default: ''

&offIds [string]
A comma separated list of document ids.
If the current document is in this list, the empty string is returned.
Provides a means of turning off the snippet for certain documents
Default: ''

&transcend [number]
Whether or not to transcend levels
when searching for the next and previous documents
Default: 1

&weblinkAction [string]
How to behave when a weblink is encountered.
Possibilities are 'link', 'skip', 'stop'
Default: 'skip'

&unpublishedAction [string]
How to behave when an unpublished document is encountered.
Possibilities are 'link', 'skip', 'stop'
Default: 'skip'

&notInMenuAction [string]
How to behave when a document is encountered that does not appear in the menu.
Possibilities are 'link', 'skip', 'stop'
Default: 'skip'

&template[string]
A template for the output
Use [~NL.rel~] to return the type of link (prev, next, parent)
Default: ''

===================================================================
Impovements:
===================================================================

This snippet works in a brute force and probably quite inefficient way...
when finding the related document and when skipping unwanted documents.
Thanks to modx's caching mechanism, it's not a big issue however.

By rolling up the logic, which currently involves iteration and multiple modx api calls, 
into a few mysql queries it could probably be made more efficient.
If anyone wants to have a go, feel free

This snippet doesn't currently do anything about phx.

===================================================================
The snippet...
===================================================================
*/
require_once($modx->config['base_path'] . 'assets/snippets/navigator/navigator.php');

$navigator = new Navigator( array(
   'rel' => $rel
   , 'stopIds' => $stopIds
   , 'offIds' => $offIds
   , 'transcend' => $transcend
   , 'weblinkAction' => $weblinkAction
   , 'unpublishedAction' => $unpublishedAction
   , 'notInMenuAction' => $notInMenuAction
   , 'template' => $template
) );

return $navigator->Calculate( );
?>

Unfortunatly I have not the skills to write my own snippet. Maybe it can be done by getting the old navigator script running.

What I don’t get is, why’s that complicated what I want? Modx shows the document tree, thus there should be something, to go through the tree as it is shown. The task would only to fetch the element before and after the current.

So we would have to put it in an array, filterd by published docs only, and put these two elements mentioned above in placeholders (prev/next) for output.

Can you also provide the code from this file (and possibly from other files in the folder assets/snippets/navigator)?
It looks like all the relevant code is there.

It’s not that simple. MODX doesn’t load the whole tree in its entirety. There are multiple DB-queries that only load the direct child-resources. For folders that are closed, the children get only loaded, once the folder is opened.
Also, the tree-structure is stored in the Ext.js-component and can’t be used by a frontend snippet.

Yes sure, and it’s only the navigator.php, furthermore only an index.html size 0:

<?php

// ===================================================================
// Snippet: Navigator
// ===================================================================
// Version: 0.1
// Date: 2008.12.17
// Author: PMS
// Licence: GPL GNU - Public
// Credit: I used some code from the Wayfinder snippet when figuring out how to do templating.

class Navigator
{

    // Internal parameters
    private $relVals;
    private $weblinkActionVals;
    private $unpublishedActionVals;
    private $notInMenuActionVals;
    private $placeHolderFieldVals;

    // User supplied parameters
    private $rel;
    private $stopIds;
    private $offIds;
    private $transcend;
    private $weblinkAction;    
    private $unpublishedAction;    
    private $notInMenuAction;    
    private $templateSource;
    private $modx;

    // Derived parameters
    private $stopIdArray;
    private $offIdArray;
    private $template;


    public function __construct( $params )
    {
        global $modx;
        $this->modx = &$modx;

        // Set allowed values
        $this->relVals = array('up', 'prev', 'next');
        $this->weblinkActionVals = array('skip', 'stop', 'link');
        $this->unpublishedActionVals = array('skip', 'stop', 'link');
        $this->notInMenuActionVals = array('skip', 'stop', 'link');
        $this->placeHolderFieldVals = array('nav.rel');
        $this->rel = 'up';

        // Set default values
        $this->stopIds = '';
        $this->offIds = '';
        $this->transcend = 1;
        $this->weblinkAction = 'skip';    
        $this->unpublishedAction = 'skip';    
        $this->notInMenuAction = 'skip';    
        $this->templateSource = '';

        $this->stopIdArray = array();
        $this->offIdArray = array();

        if ( array_key_exists( 'rel', $params ) )
        {
            if ( in_array( $params['rel'], $this->relVals ) )
            {
                $this->rel = $params['rel'];
            }
        }

        if ( array_key_exists( 'stopIds', $params ) )
        {
            $this->stopIdArray = explode( ',', str_replace(' ','', $params['stopIds'] ) );
        }

        if ( array_key_exists( 'offIds', $params ) )
        {
            $this->offIdArray = explode( ',', str_replace(' ','', $params['offIds'] ) );
        }

        if ( array_key_exists( 'transcend', $params ) )
        {
            if ( $params['transcend'] )
            {
                $this->transcend = 1;
            }
            else
            {
                $this->transcend = 0;
            }
        }

        if ( array_key_exists( 'weblinkAction', $params ) )
        {
            if ( in_array( $params['weblinkAction'], $this->weblinkActionVals ) )
            {
                $this->weblinkAction = $params['weblinkAction'];
            }
        }

        if ( array_key_exists( 'unpublishedAction', $params ) )
        {
            if ( in_array( $params['unpublishedAction'], $this->unpublishedActionVals ) )
            {
                $this->unpublishedAction = $params['unpublishedAction'];
            }
        }

        if ( array_key_exists( 'notInMenuAction', $params ) )
        {
            if ( in_array( $params['notInMenuAction'], $this->notInMenuActionVals ) )
            {
                $this->notInMenuAction = $params['notInMenuAction'];
            }
        }

        if ( array_key_exists( 'template', $params ) )
        {
            $this->templateSource = $params['template'];
        }

    }
   
    public function Calculate( )
    {
   
        // ======================================================
        // Calculation
        // ======================================================

        // Get the current document id
        $currentId = $this->modx->documentIdentifier;

        // If the snippet has been switched off for this document, don't display it
        if ( in_array( $currentId, $this->offIdArray ) )
        {
            return '';
        }
      
        // Get the content
        $this->template = $this->GetTemplate( $this->templateSource );
        if ( $this->template === FALSE )
        {
            // Could create a template based on type here...
            return '<!--navigator:1-->';
        }      

        while ( true )
        {

            // Get the parent document id
            $parentId = $this->GetParentId( $currentId );

            switch ( $this->rel )
            {
            case 'up':
                $id = $parentId;
                break;
            case 'prev':
                $id = $this->GetPreviousDocId( $currentId );      
                break;
            case 'next':
                $id = $this->GetNextDocId( $currentId );      
                break;
            default:
                return '<!--navigator:3-->';
            }
          
            if ( $id < 0 )
            {
                return '<!--navigator:4-->';
            }

            if ( $this->IsStopId( $id ) )
            {
                return '';
            }

            if ( $this->IsSkipId( $id ) )
            {
                $currentId = $id;
            }
            else
            {
                break;
            }
        }
      

        // Return the parent's sibling's id
        return $this->GetOutput( $id );      
    }

    private function GetTemplate( $source )
    {
        // based on a version in Wayfinder 2.0... which was...
        // based on version by Doze at http://modxcms.com/forums/index.php/topic,5344.msg41096.html#msg41096
        $template = '';
        if ( $this->modx->getChunk( $source ) != '')
        {
            $template = $this->modx->getChunk( $source );
        }
        else if ( substr($tpl, 0, 6) == '@FILE:' )
        {
            $template = $this->GetFileContents( substr( $source, 6 ) );
        }
        else if ( substr($tpl, 0, 6) == '@CODE:' )
        {
            $template = substr( $source, 6 );
        }
        else
        {
            $template = FALSE;
        }
        return $template;
    }

	private function GetFileContents( $filename )
    {
		// Function written at http://www.nutt.net/2006/07/08/file_get_contents-function-for-php-4/#more-210
		// Returns the contents of file name passed
		if ( ! function_exists( 'file_get_contents' ) )
        {
			$fhandle = fopen( $filename, 'r' );
			$fcontents = fread( $fhandle, filesize( $filename ) );
			fclose( $fhandle );
		}
        else
        {
			$fcontents = file_get_contents( $filename );
		}
		return $fcontents;
	}

    private function SortDocs($a, $b)
    {
        if ( $a['menuindex'] == $b['menuindex'] )
        {
            return 0;
        }
        return ($a['menuindex'] > $b['menuindex']) ? 1 : -1;
    }

    private function GetPlaceHolderFieldsArray( $tpl )
    {
        // Extract the place holders from the document...
        preg_match_all('~\[\+(.*?)\+\]~', $tpl, $matches);
        return array_unique( $matches[1] );
    }

    private function GetTVArray()
    {
        // Gets an array of all template variables
        $table = $this->modx->getFullTableName('site_tmplvars');
        $tvs = $this->modx->db->select('name', $table);
        // TODO: make it so that it only pulls those that apply to the current template
        $dbfields = array();
        while ( $dbfield = $this->modx->db->getRow( $tvs ) )
        {
            $dbfields[] = $dbfield['name'];
        }
        return $dbfields;
    }

    private function GetOutput( $id )
    {
        // Creates the output in the given format.

        // Check that the id is valid
        if ( $id < 0 )
        {
             return '<!--navigator:6-->';
        }
        
        $placeHolderFieldsArray = $this->GetPlaceHolderFieldsArray( $this->template );

        // Handle any navigator placeholders
        $nlPlaceHoldersArray = array();
        $nlPlaceHolderValuesArray = array();
        foreach ( $placeHolderFieldsArray as $item => $field )
        {
            if ( in_array( $field, $this->placeHolderFieldVals ) )
            {
                $nlPlaceHoldersArray[] = '[+' . $field . '+]';
                // $nlPlaceHolderFieldsArray[] = $field;
                // Get the values...
                switch ( $field )
                {
                case 'nav.rel':
                    $nlPlaceHolderValuesArray[] = $this->rel;
                    break;
                default:
                    return '<!--navigator:7-->';
                }
                // Remove this field from the placeHolderFieldsArray
                unset( $placeHolderFieldsArray[$item] );
            }
        }

        $tvArray = $this->GetTVArray();
        // return htmlspecialchars( print_r( $tvArray, true ) );

        $tvPlaceHoldersArray = array();
        $tvPlaceHolderFieldsArray = array();
        foreach ( $placeHolderFieldsArray as $item => $field )
        {
            if ( in_array( $field, $tvArray ) )
            {
                $tvPlaceHoldersArray[] = '[+' . $field . '+]';
                $tvPlaceHolderFieldsArray[] = $field;
                // Remove this field from the placeHolderFieldsArray
                unset( $placeHolderFieldsArray[$item] );
            }
        }
        // return htmlspecialchars( print_r( $tvPlaceHolderFieldsArray, true ) );

        // Template variables
        $tvPlaceHolderValuesArray = array();
        if ( count( $tvPlaceHoldersArray ) > 0 )
        {
            $tvPlaceHolderValuesArray = array_values(
                $this->modx->getTemplateVarOutput(
                    $tvPlaceHolderFieldsArray
                    , $id
                    )
                );
        }
            
        // return htmlspecialchars( print_r( $tvPlaceHolderValuesArray, true ) );

        $docPlaceHoldersArray = array();
        $docPlaceHolderFieldsArray = array();
        foreach ( $placeHolderFieldsArray as $item => $field )
        {
            // if ( in_array( $field, $tvArray ) )
            // {
                $docPlaceHoldersArray[] = '[+' . $field . '+]';
                $docPlaceHolderFieldsArray[] = $field;
                // Remove this field from the placeHolderFieldsArray
                // unset( $placeHolderFieldsArray[$item] );
            // }
        }
        // return htmlspecialchars( print_r( $tvPlaceHolderFieldsArray, true ) );

        // Get the data....
        // Template variables
        $docPlaceHolderValuesArray = array();
        if ( count( $docPlaceHolderFieldsArray ) > 0 )
        {
            $docPlaceHolderValuesArray = array_values(
                $this->modx->getDocument(
                    $id
                    , implode(',',$docPlaceHolderFieldsArray)
                    )
                );
        }

        return str_replace(
            array_merge(
                $nlPlaceHoldersArray
                , $tvPlaceHoldersArray
                , $docPlaceHoldersArray
                )
            , array_merge(
                $nlPlaceHolderValuesArray
                , $tvPlaceHolderValuesArray
                , $docPlaceHolderValuesArray
                )
            , $this->template
            );
      
    }

   private function IsSkipId( $id )
   {
        if ( $id < 0 )
        {
            return TRUE;
        }
        $doc = $this->modx->getDocument( $id, 'type,published,hidemenu' );
        if ( !is_array( $doc ) )
        {
            return TRUE;
        }
        if ( $this->weblinkAction == 'skip' && $doc['type'] == 'reference')
        {
            return TRUE;
        }
        if ( $this->unpublishedAction == 'skip' && ! $doc['published'])
        {
            return TRUE;
        }
        if ( $this->notInMenuAction == 'skip' && $doc['hidemenu'] )
        {
            return TRUE;
        }
        return FALSE;
        
    }

    private function IsStopId( $id )
    {
        if ( $id < 0 )
        {
            return TRUE;
        }
        if ( in_array( $id, $this->stopIdArray ) )
        {
            return TRUE;
        }
        $doc = $this->modx->getDocument( $id, 'type,published,hidemenu' );
        if ( !is_array( $doc ) )
        {
            return TRUE;
        }
        if ( $this->weblinkAction == 'stop' && $doc['type'] == 'reference')
        {
            return TRUE;
        }
        if ( $this->unpublishedAction == 'stop' && ! $doc['published'])
        {
            return TRUE;
        }
        if ( $this->notInMenuAction == 'stop' && $doc['hidemenu'] )
        {
            return TRUE;
        }
        return FALSE;
        
    }

    private function GetParentId( $id )
    {
        // Gets the id of the parent.
        // If the document is the root, and so has no parent, -1 is returned
        if ( $id == 0 )
        {
            return -1;
        }
        $currentDoc = $this->modx->getDocument( $id, 'parent' );
        return $currentDoc['parent'];
    }

    private function GetFirstChildId( $id )
    {
        // Gets the id of the first child of the document
        // Returns -1 if it can't find one

        $firstChildId = -1;

        // Get the children
        $children = $this->modx->getDocumentChildren( $id, 1, '0', $fields='id, menuindex' );

        // Calculate the number of children
        $nChildren = count( $children );

        if ( $nChildren > 0 )
        {
            // Sort the children by menuindex
            usort( $children, array( 'Navigator', 'SortDocs' ) );

            // Get the id of the first child
            $firstChildId = $children[0]['id'];

            return $firstChildId;
        }

        return $firstChildId;

    }

    private function GetLastChildId( $id )
    {
        // Gets the id of the last child of the document
        // Returns -1 if it can't find one

        $lastChildId = -1;

        // Get the children
        $children = $this->modx->getDocumentChildren( $id, 1, '0', $fields='id, menuindex' );

        // Calculate the number of children
        $nChildren = count( $children );

        if ( $nChildren > 0 )
        {
            // Sort the children by menuindex
            usort( $children, array( 'Navigator', 'SortDocs' ) );

            // Get the id of the last child
            $lastChildId = $children[$nChildren-1]['id'];

            return $lastChildId;
        }

        return $lastChildId;

    }

    private function GetSiblingId( $id )
    {
        // Gets the next sibling.
        // Returns -1 if one doesn't exist

        $siblingId = -1;

        // If the document is the document root, then it has no siblings
        if ( $id == 0 )
        {
            return -1;
        }

        // Get the parent document id
        $parentId = $this->GetParentId( $id );
        // $currentDoc = $this->modx->getDocument( $id, 'parent' );
        // $parentId = $currentDoc['parent'];


        // Get the immediate siblings (and the current document)
        $siblings = $this->modx->getDocumentChildren( $parentId, 1, '0', $fields='id, menuindex' );

        // Calculate the number of siblings
        $nSiblings = count( $siblings ) - 1;

        // Sort the children by menuindex
        usort( $siblings, array( 'Navigator', 'SortDocs' ) );

        $currentIndex = -1;
        // Find the current document in the list of siblings
        foreach ( $siblings as  $index => $sibling )
        {
            if ( $sibling['id'] == $id )
            {
                $currentIndex = $index;
                break;
            }
        }
        if ($currentIndex == -1)
        {
            return $siblingId;
        }

        switch ( $this->rel )
        {
        case 'prev':
            if ( $currentIndex > 0 )
            {
                $siblingId = $siblings[$currentIndex-1]['id'];
                return $siblingId;
            }
            break;
        case 'next':
            if ( $currentIndex < $nSiblings )
            {
                $siblingId = $siblings[$currentIndex+1]['id'];
                return $siblingId;
            }
            break;
        default:
            return $siblingId;
        }

        return $siblingId;
    }

    private function GetPreviousDocId( $id )
    {
        if ( $this->transcend )
        {
            // If the current document has a previous sibling, then get its last child

            // Check if the current document has a previous sibling
            $siblingId = $this->GetSiblingId( $id );

            // If it has a sibling...
            while ( $siblingId >= 0 )
            {
                // Get the last child of the document
                $lastChildId = $this->GetLastChildId( $siblingId );

                // If it doesn't have a child, then stop here
                if ( $lastChildId < 0 )
                {
                    return $siblingId;
                }

                // Go down the tree
                $siblingId = $lastChildId;

            }

            // The current document doesn't have a previous sibling, so get its parent.
            $parentId = $this->GetParentId( $id );

            if ( $parentId >= 0)
            {
                return $parentId;
            }

            return -1;         
        }
        else
        {

            // A sibling was required. Get the sibling
            $siblingId = $this->GetSiblingId( $id );

            // If the sibling has been found, then create the link
            if ( $siblingId >= 0 )
            {
                return $siblingId;
            }

            return -1;
        }

        return -1;
    }

    private function GetNextDocId( $id )
    {
        if ( $this->transcend )
        {
            // If the current document has children, then get the first child.
            $firstChildId = $this->GetFirstChildId( $id );

            if ( $firstChildId >= 0 )
            {
                // Return the first page
                return $firstChildId;
            }

            // otherwise, try to get the next sibling.
            $siblingId = $this->GetSiblingId( $id );

            if ( $siblingId >= 0)
            {
                // Return the first page
                return $siblingId;
            }

            // If there is no next sibling, get the parent's sibling.
            $parentId = $this->GetParentId( $id );

            // Check if the parent is valid
            while ( $parentId >= 0 )
            {
                $parentsSiblingId = $this->GetSiblingId( $parentId );

                if ( $parentsSiblingId >= 0 )
                {
                    // Return the parent's sibling's id
                    return $parentsSiblingId;
                }

                // Repeat the last step until completion
                $parentId = $this->GetParentId( $parentId );
            }      

            return -1;

        }
        else
        {

            // A sibling was required. Get the sibling
            $siblingId = $this->GetSiblingId( $id );

            // If the sibling has been found, then create the link
            if ( $siblingId >= 0 )
            {
                return $siblingId;
            }

            return -1;
        }

        return -1;
    }


}
?>

Ok, I took the code and adapted it to MODX 3.

The transport package for the extra is here on Github:

To install the extra, go to “Extras” → “Installer” in your MODX 3 manager, and drag/drop the Zip-File into the grid.


I haven’t tested the code extensively. It’s quite possible that there are still bugs.

Some functionality has been removed:

  • TV values can’t be used in the template anymore.
  • Inline templates (@CODE:) and file templates (@FILE:) are no longer supported. Only normal MODX chunks can be used as the template.

Wow, you’ve done a great job, thank you so much!

For me it works, that’s great, it parses through the doc tree and jumps from last child to next parent, which none of the other prev-next scripts does.

The only thing I couldn’t get to work, but this is not part of the navigator, is building the a-tag in the template. For type="text/html" I use type="[[*content_type]]" but this gives me type="1"

No problem, I can hardcode it, but maybe there is a better way?

Kind regards
Andre

1 Like

The content types are now in a separated table (modx_content_type) and “1” is the foreign key. I guess this was different in MODX 0.9.6.3.


I updated the code to also query the mime-type of the context-type.
The placeholder [[+ct_mime_type]] should now output "text/html" (or whatever the mime-type of the resource is).

works like a charm, thanks again!

This topic was automatically closed 2 days after discussion ended and a solution was marked. New replies are no longer allowed. You can open a new topic by clicking the link icon below the original post or solution and selecting “+ New Topic”.