We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 22851
    • 805 Posts
    PHP is saying that it found unexpected syntax on line 16 of the file /www/solovets/www/htdocs/solovets/assets/snippets/navigator/navigator.php.

    Have you edited this file? I have just downloaded a fresh version from MODx and the first 20 or so lines look like this:

    <?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;


    I can’t see a problem there. The file should have the following md5sum: [tt]bd063b091c274b1ba04185a600af703a[/tt]

    If yours doesn’t then it’s possible that your download was corrupted. I suggest you try to download it again and reinstall.

    EDIT: Also please can you tell me what your php version is? You can get it via the manager: Reports->System Info then select View next to phpInfo.


    Paul
      YAMS: Yet Another Multilingual Solution for MODx
      YAMS Forums | Latest: YAMS 1.1.9 | YAMS Documentation
      Please consider donating if you appreciate the time and effort spent developing and supporting YAMS.
      • 27968
      • 19 Posts
      Paul, thank you for your answer. I’ve jast reinstall Navagator (http://modxcms.com/extras.html?view=package/view&package=314) but got the same problem.

      PHP Version 4.3.9
      MODx MODx 0.9.6.1p2
      Charset Windows-1251 (cp1251) (I’m from Russia)
        • 22851
        • 805 Posts
        Ahh. I see the problem. I have used PHP 5 style class declarations. You have two options:

        1) Upgrade to the latest version of PHP. (For security and stability reasons, that’s recommended.)
        2) Try replacing your navigator.php by the attached version. I have removed all public and private declarations. It might just work, but I can’t guarantee it.

        Hey... Where has the attachment button gone? It has disappeared. Here is my attempt at PHP 4 compatible code then:

        <?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
            var $relVals;
            var $weblinkActionVals;
            var $unpublishedActionVals;
            var $notInMenuActionVals;
            var $placeHolderFieldVals;
        
            // User supplied parameters
            var $rel;
            var $stopIds;
            var $offIds;
            var $transcend;
            var $weblinkAction;    
            var $unpublishedAction;    
            var $notInMenuAction;    
            var $templateSource;
            var $modx;
        
            // Derived parameters
            var $stopIdArray;
            var $offIdArray;
            var $template;
        
        
            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'];
                }
        
            }
           
            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 );      
            }
        
            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;
            }
        
        	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;
        	}
        
            function SortDocs($a, $b)
            {
                if ( $a['menuindex'] == $b['menuindex'] )
                {
                    return 0;
                }
                return ($a['menuindex'] > $b['menuindex']) ? 1 : -1;
            }
        
            function GetPlaceHolderFieldsArray( $tpl )
            {
                // Extract the place holders from the document...
                preg_match_all('~\[\+(.*?)\+\]~', $tpl, $matches);
                return array_unique( $matches[1] );
            }
        
            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;
            }
        
            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
                    );
              
            }
        
           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;
                
            }
        
            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;
                
            }
        
            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'];
            }
        
            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;
        
            }
        
            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;
        
            }
        
            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;
            }
        
            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;
            }
        
            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;
            }
        
        
        }
        ?>
          YAMS: Yet Another Multilingual Solution for MODx
          YAMS Forums | Latest: YAMS 1.1.9 | YAMS Documentation
          Please consider donating if you appreciate the time and effort spent developing and supporting YAMS.
          • 27968
          • 19 Posts
          Hmm... To upgrade to the latest version of PHP - it’s a really problem.

          I copy-past your code, now the server gives

          « MODx Parse Error »
          MODx encountered the following error while attempting to parse the requested resource:
          « PHP Parse Error »

          PHP error debug
            Error: in_array(): Wrong datatype for second argument
            Error type/ Nr.: Warning - 2
            File: /www/solovets/www/htdocs/solovets/assets/snippets/navigator/navigator.php
            Line: 136
            Line 136 source: if ( in_array( $currentId, $this->offIdArray ) )


          Parser timing
            MySQL: 0.0090 s (3 Requests)
            PHP: 0.0308 s
            Total: 0.0399 s

          So... If it’s very difficult to correct the code? (Sorry for such big number of questions, but I don’t know php at all)
            • 22851
            • 805 Posts
            Are you using the &offIds snippet parameter. If so, what value have you assigned it? Thanks.
              YAMS: Yet Another Multilingual Solution for MODx
              YAMS Forums | Latest: YAMS 1.1.9 | YAMS Documentation
              Please consider donating if you appreciate the time and effort spent developing and supporting YAMS.
              • 22851
              • 805 Posts
              Ahhh. I see. With PHP 4 classes the constructor must have the same name as the class, so the constructor wasn’t being called and $this->offIdArray wasn’t being initialised. I have corrected it. Please try the following:

              <?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
                  var $relVals;
                  var $weblinkActionVals;
                  var $unpublishedActionVals;
                  var $notInMenuActionVals;
                  var $placeHolderFieldVals;
              
                  // User supplied parameters
                  var $rel;
                  var $stopIds;
                  var $offIds;
                  var $transcend;
                  var $weblinkAction;    
                  var $unpublishedAction;    
                  var $notInMenuAction;    
                  var $templateSource;
                  var $modx;
              
                  // Derived parameters
                  var $stopIdArray;
                  var $offIdArray;
                  var $template;
              
              
                  function Navigator( $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'];
                      }
              
                  }
                 
                  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 );      
                  }
              
                  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;
                  }
              
              	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;
              	}
              
                  function SortDocs($a, $b)
                  {
                      if ( $a['menuindex'] == $b['menuindex'] )
                      {
                          return 0;
                      }
                      return ($a['menuindex'] > $b['menuindex']) ? 1 : -1;
                  }
              
                  function GetPlaceHolderFieldsArray( $tpl )
                  {
                      // Extract the place holders from the document...
                      preg_match_all('~\[\+(.*?)\+\]~', $tpl, $matches);
                      return array_unique( $matches[1] );
                  }
              
                  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;
                  }
              
                  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
                          );
                    
                  }
              
                 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;
                      
                  }
              
                  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;
                      
                  }
              
                  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'];
                  }
              
                  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;
              
                  }
              
                  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;
              
                  }
              
                  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;
                  }
              
                  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;
                  }
              
                  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;
                  }
              
              
              }
              ?>


              I’d be interested to know if it works. Thanks
                YAMS: Yet Another Multilingual Solution for MODx
                YAMS Forums | Latest: YAMS 1.1.9 | YAMS Documentation
                Please consider donating if you appreciate the time and effort spent developing and supporting YAMS.
                • 27968
                • 19 Posts
                Paul, it works!!!

                Thank you very much for your job and for your attention!

                P.S.

                Navigator - is a very usefull snippet. It gives much more opportunities to make pagination than ditto or some other snippets I’ve tried.
                  • 1841
                  • 141 Posts
                  Hello,
                  I have been using this snippet as a way of navigating for my Prev / Next list of books, however it doesn’t seem to work correctly on my site. On some pages it shows the correct prev / next links, on other it skips some pages and on others doesn’t show a link anywhere.

                  Some of these pages are 2 folders deep, and some are in unpublished folders, could this be the issue?

                  my site is http://www.sciencefictionandfantasy.co.uk

                  An example page is:

                  http://www.sciencefictionandfantasy.co.uk/the-riven-kingdom.htm

                  This page should show a previous link to http://www.sciencefictionandfantasy.co.uk/the-spooks-mistake.htm but doesn’t, and /the-spooks-mistake.htm misses out all pages until magician.htm despite many pages in between.

                  The calls I am using are:
                  [[Navigator? &rel=`prev` &template=`PrevChunk` &notInMenuAction=`skip` &transcend=`3` &unpublishedAction=`skip` ]]
                  [[Navigator? &rel=`next` &template=`NextChunk` &notInMenuAction=`skip` &transcend=`3` &unpublishedAction=`skip` ]]

                  Any Ideas?
                    • 22851
                    • 805 Posts
                    I notice that you are using cacheable snippet calls. Have you tried clearing your cache (or switching to uncacheable snippet calls)?

                    If that doesn’t solve the problem, then I’ll need more information to be able to try to debug the problem. Information about your document tree in the vicinity of the place where it doesn’t work, including the the published and show in menu status of the affected documents would be useful. An annotated screenshot of your document tree might help. Ideally I would have enough information to be able to try to reproduce the problem.

                    Thanks.
                      YAMS: Yet Another Multilingual Solution for MODx
                      YAMS Forums | Latest: YAMS 1.1.9 | YAMS Documentation
                      Please consider donating if you appreciate the time and effort spent developing and supporting YAMS.
                      • 1841
                      • 141 Posts
                      @PMS

                      Thanks for the reply, I have tried the snippets uncached and still no joy, I think it must have something to do with the doc ID’s

                      Here is a sample of the tree, italics are unpublished, bold show in menu.

                      Joseph Delaney (1478)
                                 Wardstone Chronicles (1479)
                                                  The Spooks Apprentice (1480)
                                                   The Spooks Curse (1481)
                                                   The Spooks Secret (1482)
                                                   The Spooks Battle (1483)
                                                   The Spooks Mistake (1475)

                      Karen Miller (1222)
                               Godspeaker (1223)

                                           The Riven Kingdom (815)
                                           Hammer of God (848)

                      Ken Scholes (1231)
                             Lamentation (1074)
                      Katherine Kerr (877)
                              The Shadow Isle (791)

                      Hope that helps, does it look at the doc ID or can it sort by Menu ID?

                      I have done some more experimenting and it seems to be an issue with unpublished folders, it won’t go up a level (or 2) through them, nor will it go through them to get to the published pages, although I have specified skipping unpublished.

                      For Example, /the-spooks-apprentice.htm will go to the previous folder that has been published, and show the document (/the-legend-of-sigurd-and-gudrun.htm) but the others shown here won’t leave their folder, and /the-spooks-apprentice.htm will not show any of these but goes straight to the next published page in a published folder.