We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 34022 ☆ A M B ☆
    • 91 Posts
    I made this looping snippet for outputting multiple chunks with a simple array of placeholders. I’m posting it here for feedback before adding it to the repository. Let me know what you think.

    Purpose: outputs a series of templated chunks from an array of placeholders. Yes, Revolution does make it simple to use chunks in the form of [[$chunk? &placeholder=`value` &anotherplaceholder=`value`]], but when you have ten of those in a row or more, it can get unwieldy. So this snippet makes it easier to output and manage them.

    Example Usage: Output a bunch of text fields in a form, a list of links, a quick javascript slider, or anything else where a custom snippet or database table is overkill.

    Instructions: copy and paste this into a snippet called "Loop". Call with [[Loop? &tpl=`chunkname` &loop=`{"placeholder":"value1,value2,value3","placeholder2":"value1,value2,value3"}`]] to output three chunks with [[+placeholder1]] and [[+placeholder2]]. (and check out the commented section at the top for a bunch of other alternatives, including MODx-style arrays.)

    Loop Snippet Code (outdated - see later post for updated version):
    <?php
    /**
     * Loop
     *
     * A looping snippet that loops through one or more arrays of placeholders to output several chunks at once (or separates with separators). 
     *
     * @author Oleg Pryadko (websitezen.com)
     * @copyright Copyright 2011, Oleg Pryadko
     * @version 1 - Jan 30, 2011
     * @license GPL (any version)
     *
     *
     * PARAMETERS
     *
     * &tpl - Name of a chunk serving as a template for the loop
     * [NOTE: if not provided, will use separators instead]
     *
     * &loop - JSON array of values to loop through (with or without placeholders). If loop is left blank, defaults to numbers.
     *
     * &numbers - (boolean). Adds numbers as placeholder values (if loop is set, adds them in addition to existing placeholders).
     * &min - (if using numbers) Number to start with. Default is 0. Can be negative.
     * &max - (if using numbers) Number to end with. Default is 3. Can be negative.
     * &step - (if using numbers) Number to add with every iteration. Default is 1. Can be negative.
     * 
     * &ph (or placeholder) - (optional) single placeholder or comma-separated list of placeholders
     * [IMPORTANT: must be in the same order as &loop statement. If using numbers, put the numbers placeholder last.]
     * 
     * &phSimple - &ph alternative - use MODx-style separation in &loop option (option==value||another option==another value)
     *
     * &prefix - Prefix to use before numbers if no placeholder is set. Defaults to "loop_" (e.g. [[+loop_1]], [[+loop_2]], etc...)
     *
     * &separator - Separator to put between chunks. If no template (&tpl) is provided, separate content with this (default is "\n")
     * &separatorInner - If no template (&tpl) is provided, separate multiple placeholders with this (default is " ")
     * &idx - Placeholder to use for idx. Setting to 0 will disable. (default is "idx")
     * 
     * &toPlaceholder - Set placeholder
     * &default - If for whatever reason the result is empty, return this.
     * &debug - Print_r debug arrays
     *
     *
     * PLACEHOLDERS
     *
     * Loop adds an [[+idx]] placeholder, which holds the iteration number (starting from 1).
     * Use idx with the ":mod" output filter to add odd/ even logic to your templates.
     * 
     * When no placeholders (or not enough placeholders) are provided, Loop
     * makes its own placeholders by appending numbers to the prefix (starting from 0).
     * For example, if your prefix is "loop_" (the default prefix), you will get 
     * [[+loop_0]], [[+loop_1]], [[+loop_2]], etc....
     *
     *
     *
     * EXAMPLES
     *
     * Using &loop WITHOUT &ph:
     * Example with one placeholder only: &loop=`{"fistname":"Homer,Marge,Lisa,Bart"}`
     * Example with one placeholder only (results in [[+loop_0]] placeholder]]: &loop=`Homer,Marge,Lisa,Bart`
     * Example with multiple placeholders: {"firstname":"Homer,Marge,Lisa,Bart","lastname":"Simpson,Simpson,Simpson,Simpson","phone":"1-555-123-4567,1-555-123-4567,,"}
     * Example with multiple placeholders (results in [[+loop_0]], [[+loop_1]] and  [[+loop_2]] placeholders): {"0":"Homer,Marge,Lisa,Bart","1":"Simpson,Simpson,Simpson,Simpson","2":"1-555-123-4567,1-555-123-4567,,"}
     * Example with more complicated JSON: {"name":{"0":"Simpson, Homer","1":"Simpson, Marge","2":"Simpson, Lisa","3":"Simpson, Bart"},"phone":"1-555-123-4567,1-555-123-4567,,"}
     * 
     * Using &loop WITH &ph:
     * &ph example with one placeholder only: &ph=`firstname` &loop=`Sue,Joe,Mary,Bo`
     * &ph example with multiple placeholders (JSON seems to need numbers starting from zero to signify multiple arrays): &ph=`firstname,lastname` &loop=`{"0":"Sue,Mary,Bilbo,Gandalf","1":"Smith,Brown,Baggins,Grey"}`
     *
     * Using &loop WITH &phSimple (MODx-style dividers):
     * &phSimple example with one placeholder: &phSimple=`firstname` &loop=`John==Joe==Lisa==Bart`
     * &phSimple example with multiple placeholders: &phSimple=`firstname,lastname,phone` &loop=`John==Joe==Lisa==Bart||Simpson==Simpson==Simpson==Simpson||1-555-123-4567==1-555-123-4567`
     * Note: the last two phone numbers are automatically filled in with an empty string
     *
     * Example using &numbers: [[!Loop? &ph=`name,number` &numbers=`1` &min=`3` &max=`0` &step=`-1` &loop=`Mary,Joe,Brian` &separator=`<br />` &tpl=`loopTpl`]]
     *
     *
     * USES
     * 
     * I use templated chunks for outputting FormIt fields. I have a chunk for text field, hidden field, etc...
     * If I need a form with 20 text fields in a row, a looping snippet like this is perfect.
     * 
     * It's also useful for just about any other simple repetition need where using a custom snippet is overkill.
     * Can easily be combined with other snippets (put them in the template chunks or use them to generate parameters).
     * 
     */
    
    
    $numbers = (bool)$modx->getOption('numbers',$scriptProperties,0);
    $min = $modx->getOption('min',$scriptProperties,0);
    $max = $modx->getOption('max',$scriptProperties,3);
    $step = $modx->getOption('step',$scriptProperties,1);
    
    $loop = $modx->getOption('loop',$scriptProperties,'');
    if (empty($loop)) {$numbers = 1;}
    
    /* set placeholder options */
    $ph = $modx->getOption('ph',$scriptProperties,'');
    if (empty($ph)) {$ph = $modx->getOption('placeholder',$scriptProperties,'');}
    if (empty($ph)) {$ph = $modx->getOption('placeholders',$scriptProperties,'');}
    if (empty($ph)) {$phSimple = $modx->getOption('phSimple',$scriptProperties,'');}
    if (!empty($phSimple)) {$ph = $phSimple;}
    
    /* set templating options */
    $tpl = $modx->getOption('tpl',$scriptProperties,''); 
    if (empty($tpl)) {$tpl = $modx->getOption('template',$scriptProperties,'');}
    $separator = $modx->getOption('separator',$scriptProperties,"\n");
    if (!$tpl) {$separatorInner = $modx->getOption('separatorInner',$scriptProperties," ");}
    $toPlaceholder = $modx->getOption('toPlaceholder',$scriptProperties,false);
    
    /* set miscellaneous options */
    $prefix = $modx->getOption('prefix',$scriptProperties,'loop_');
    $debug = $modx->getOption('debug',$scriptProperties,0);
    $default = $modx->getOption('default',$scriptProperties,'');
    $useIdx = $modx->getOption('idx',$scriptProperties,'idx');
    
    $output = '';
    
    if ($numbers) {
    	$numbersArray = array();
    	$numbersArray[0] = array();
    	$numDif = $max-$min;
    	if($numDif>0 && $step>0) {
    		for($i=$min;$i<$max;$i=$i+$step) {$numbersArray[0][] = $i;}
    	} elseif($numDif<0  && $step<0) {
    		for($i=$min;$i>$max;$i=$i+$step) {$numbersArray[0][] = $i;}
    	} else {$modx->log(modX::LOG_LEVEL_ERROR,'[Loop] Numbers function is not properly formed. Check min, max, and step parameters.'); $numbers = 0;}
    
    	if ($numbers && $loop) {$mergeNumbers = 1;}
    	elseif ($numbers && !$loop) {$loop = $modx->toJSON($numbersArray);}
    }
    if (!$numbers && !$loop) {$modx->log(modX::LOG_LEVEL_ERROR,'[Loop] Neither numbers nor loop is set. Nothing to do!'); return $default;}
    
    /* make &loop into a basic array */
    if (empty($phSimple))  {
    	$loopTempArray = $modx->fromJSON($loop);
    	if (!is_array($loopTempArray)) {
    		$loopTempArray = array(0 => explode(',',$loop));
    	}
    } else {
    	$loopArrayOuter = explode('||',$loop);
    	$loopTempArray = array();
    	foreach ($loopArrayOuter as $key => $value) {
    		$loopTempArray[$key] = explode('==',$value);
    	}
    	unset($loopArrayOuter);
    }
    if ($mergeNumbers) {$loopTempArray = array_merge($loopTempArray,$numbersArray);}
    if ($debug) {$output .= 'loopTempArray (one): '.print_r($loopTempArray,1)."<br />\n";}
    
    /* make array in the format of placeholder => valuesToLoopThrough */
    if (!empty($ph)) {
    	/* placeholder in a separate array. Compbine placeholders with loopArray */
    	$placeholderArray = explode(',',$ph);
    	$phArray = array();
    
    	/* remove numeric placeholders and replace with sequential numbers */
    	$placeholderCounter = 0;
    	foreach ($placeholderArray as $value) {
    		if(is_numeric($value)) {
    		  $phArray[] = $placeholderCounter;
    		  $placeholderCounter++;
    		} else {
    		  $phArray[] = $value;
    		}
    	}
    	if ($debug) {$output .= 'phArray: '.print_r($phArray,1).'<br />';}
    	
    	/* make sure placeholder array and value array are the same size and that values are arrays */
    	$loopCountDiff = count($phArray) - count($loopTempArray);
    	if ($loopCountDiff >= 1) {
    	/* There are more placeholders than values. Add empty values */
    		for($i = $loopCountDiff; $i>=1; $i--) {
    			$loopTempArray[] = array(0 => '');
    		}
    		if ($debug) {$output .= 'loopTempArray (loopCountDiff >= 1): '.print_r($loopTempArray,1).'<br />';}
    	} elseif ($loopCountDiff <= -1) {
    		/* There are more values than placeholders. Add sequential number placeholders. */
    		for($i = $loopCountDiff; $i<=-1; $i++) {
    			$phArray[] = $prefix.$placeholderCounter;
    			$placeholderCounter++;
    		}
    		if ($debug) {$output .= 'phArray (loopCountDiff <= 1): '.print_r($phArray,1).'<br />';}
    		unset($placeholderCounter);
    	}
    
    	/* compbine placeholders and values */
    	$phArray;
    	$loopTempArray = array_combine($phArray,$loopTempArray);
    	if ($debug) {$output .= 'loopTempArray (with ph): '.print_r($loopTempArray,1).'<br />';}
    }
    
    /* placeholder are now definitely in array. Make sure formatting is correct (placeholder => valueArray) */
    $loopArray = array();
    $loopCount = 0;
    if ($debug) {$output .= 'loopTempArray (two): '.print_r($loopTempArray,1).'<br />';}
    foreach ($loopTempArray as $placeholder => $value) {
      $loopCount++;
      
      /* value must be an array */
      if (!is_array($value)) {
    	$valueArray = explode(",",$value);
      }
      else {$valueArray = $value;}
      
      /* placeholder must be a string */
      if (is_array($placeholder)) {
        $modx->log(modX::LOG_LEVEL_ERROR,'[Loop] Placeholder "'.$placeholder.'" cannot be an array.');
        $loopArray[$prefix.$loopCount] = $valueArray;
      } elseif (is_numeric($placeholder)) {
        $loopArray[$prefix.$placeholder] = $valueArray;
      } elseif (empty($placeholder)) {
        $loopArray[$prefix.$loopCount] = $valueArray;
      } else {
        $loopArray[$placeholder] = $valueArray;
      }
    }
    if ($debug) {$output .= 'loopArray (three): '.print_r($loopArray,1).'<br />';}
    
    /* rearrange array to make final looping array */
    $loopArrayFinal = array();
    $loopValueCount = array();
    foreach ($loopArray as $placeholder => $valueArray) {
    	$loopValueCount[$placeholder] = count($valueArray);
    }
    $loopMaxCount = max($loopValueCount);
    if ($debug) {$output .= 'max($loopValueCount): '.$loopMaxCount.'<br />';}
    $idx = 0;
    for($i=$loopMaxCount;$i>0;$i--) {
    	$loopArrayFinal[$idx] = array();
    	if (!empty($useIdx)) {
    		$loopArrayFinal[$idx][$useIdx] = $idx + 1;
    	}
    	foreach ($loopArray as $placeholder => $valueArray) {
    		if (isset($valueArray[$idx])) {
    			$loopArrayFinal[$idx][$placeholder] = $valueArray[$idx];
    		} else {
    			$loopArrayFinal[$idx][$placeholder] = '';
    		}
    	}
    	$idx++;
    }
    
    if (count($loopArrayFinal) == 0) {$modx->log(modX::LOG_LEVEL_ERROR,'[Loop] returned no results.'); return $default;}
    if ($debug) {$output .= 'loopArrayFinal: '.print_r($loopArrayFinal,1).'<br />';}
    
    /* Loop through loopArrayFinal to produce templated output */
    $idx = 0;
    foreach ($loopArrayFinal as $placeholder => $valueArray) {
      if ($idx > 0) {$output .= $separator;}
      $idx++;
      if (!empty($tpl)) {
        /* if template chunk is given, add chunk with placeholders to output */
        $output .= $modx->getChunk($tpl,$valueArray);
      } else {
        /* else, just separate values with separator */
        $output .= implode($valueArray,$separatorInner);
      }
    }
    if (!empty($toPlaceholder)) {
        $modx->setPlaceholder($toPlaceholder,$output);
        return '';
    } else return $output;
    

      WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area
      • 18373 ☆ A M B ☆
      • 3,141 Posts
      Looks nice! Can definitely see use for this wink
        Mark Hamstra • Developer spending his days working on Premium Extras and a MODX Site Dashboard with the ability to remotely upgrade MODX and extras to make the MODX world a little better.

        Tweet me @mark_hamstra, check my infrequent blog at markhamstra.com, my slightly more frequent ramblings at MODX.today or see code at Github.
        • 34022 ☆ A M B ☆
        • 91 Posts
        Still working on it, but here is the latest version. I changed a lot of the defaults, so if you used the previous version, please see the new comments.

        I think the only major thing left to do is to allow a different order of looping. Right now you have to loop in "chunk1a==chunk2a==chunk3a||chunk1b==chunk2b==chunk3b", but some people may want to use "chunk1a==chunk1b||chunk2a==chunk2b||chunk3a==chunk3b". I also want to make the default == and || separators configurable.

        <?php
        /**
         * Loop
         *
         * A looping snippet that loops through one or more arrays of placeholders to output several chunks at once (or separates with separators). 
         *
         * @author Oleg Pryadko ([email protected])
         * @copyright Copyright 2011, Oleg Pryadko
         * @version 1 - Jan 30, 2011
         * @license GPL (any version)
         *
         * To Do: allow on/ off switch of JSON-style vs. MODx-style arrays separate from the &ph placeholder
         *
         * PARAMETERS
         *
         * &tpl - Name of a chunk serving as a template for the loop
         * [NOTE: if not provided, will use separators instead]
         *
         * &loop - JSON array of values to loop through (with or without placeholders). If loop is left blank, defaults to numbers.
         *
         * &numbers - (boolean). Adds numbers as placeholder values (if loop is set, adds them in addition to existing placeholders).
         * &min - (if using numbers) Number to start with. Default is 0. Can be negative.
         * &max - (if using numbers) Number to end with. Default is 3. Can be negative.
         * &step - (if using numbers) Number to add with every iteration. Default is 1. Can be negative.
         * 
         * &ph (or placeholder) - (optional) single placeholder or comma-separated list of placeholders
         * [IMPORTANT: must be in the same order as &loop statement. If using numbers, put the numbers placeholder last.]
         * &phSimple - &ph alternative - use MODx-style separation in &loop option (option==value||another option==another value)
         *
         * &prefix - Prefix to use before numbers if no placeholder is set. Defaults to "loop_" (e.g. [[+loop_1]], [[+loop_2]], etc...)
         *
         * &static - Static placeholders that are the same in every loop. 
         * If phSimple is active, use MODx-style arrays (&static=`lastname==Simpson||color==yellow`). 
         * Otherwise, use JSON-style array (&static=`{"lastname":"Simpson","color":"yellow"}`)
         *
         * &separator - Separator to put between chunks. If no template (&tpl) is provided, separate content with this (default is "\n")
         * &separatorInner - If no template (&tpl) is provided, separate multiple placeholders with this (default is " ")
         * &idx - Placeholder to use for idx. Setting to 0 will disable. (default is "idx")
         * 
         * &toPlaceholder - Set placeholder
         * &default - If for whatever reason the result is empty, return this.
         * &debug - Print_r debug arrays
         *
         *
         * PLACEHOLDERS
         *
         * Loop adds an [[+idx]] placeholder, which holds the iteration number (starting from 1).
         * Use idx with the ":mod" output filter to add odd/ even logic to your templates.
         * 
         * When no placeholders (or not enough placeholders) are provided, Loop
         * makes its own placeholders by appending numbers to the prefix (starting from 0).
         * For example, if your prefix is "loop_" (the default prefix), you will get 
         * [[+loop_0]], [[+loop_1]], [[+loop_2]], etc....
         *
         *
         *
         * EXAMPLES
         *
         * Using &loop WITHOUT &ph (default MODx-style arrays):
         * - one placeholder only: [[Loop? &tpl=`loopTpl` &loop=`fistname==Homer==Marge==Lisa==Bart}`]]
         * - multiple placeholders: [[Loop? &tpl=`loopTpl` &loop=`firstname==Homer==Marge==Lisa==Bart||lastname==Simpson==Simpson==Simpson==Simpson||phone==1-555-123-4567==1-555-123-4567===="`]]
         * - using auto placeholders (results in [[+loop_0]], [[+loop_1]] and  [[+loop_2]] placeholders): [[Loop? &tpl=`loopTpl` &loop=`==Homer==Marge==Lisa==Bart||==Simpson==Simpson==Simpson==Simpson||==1-555-123-4567==1-555-123-4567===="`]]
         *
         * NOTE: if you don't specify a template with &tpl, Loop will DISABLE the first value as placeholder even if you don't specify &ph
         * So [[Loop? &loop=`==2==1` &separator=`=` &separatorInner=`+`]] will result in 1+=2+2=3+1, not 1+1=2+1 as normally expected without &ph
         * (If you are wondering where the other numbers are coming from, it is from the IDX. Use &idx=`0` to disable)
         *
         * Using &loop WITH &ph=`` (default MODx-style arrays):
         * - one placeholder: [[Loop? &tpl=`loopTpl` &ph=`firstname` &loop=`John==Joe==Lisa==Bart`]]
         * - multiple placeholders: 
         *     [[Loop? &tpl=`loopTpl` &ph=`firstname,lastname,phone` &loop=`John==Joe==Lisa==Bart||Simpson==Simpson==Simpson==Simpson||1-555-123-4567==1-555-123-4567`]]
         *     Note: the last two phone numbers are automatically filled in with an empty string
         *
         * JSON: Using &loop WITHOUT &ph AND &json=`1` (the alternative JSON-style arrays):
         * - one placeholder only: [[Loop? &tpl=`loopTpl` &loop=`{"fistname":"Homer,Marge,Lisa,Bart"}`]]
         * - multiple placeholders: [[Loop? &tpl=`loopTpl` &loop=`{"firstname":"Homer,Marge,Lisa,Bart","lastname":"Simpson,Simpson,Simpson,Simpson","phone":"1-555-123-4567,1-555-123-4567,,"}`]]
         * - one automatic placeholder ([[+loop_0]]):  [[Loop? &tpl=`loopTpl` &loop=`Homer,Marge,Lisa,Bart`]]
         * - custom prefix with multiple automatic placeholders ([[+customprefix_0]], [[+customprefix_1]] and  [[+customprefix_2]] ):  [[Loop? &tpl=`loopTpl` &prefix=`customprefix` &loop=`{"0":"Homer,Marge,Lisa,Bart","1":"Simpson,Simpson,Simpson,Simpson","2":"1-555-123-4567,1-555-123-4567,,"}`]]
         * - more complicated JSON: [[Loop? &tpl=`loopTpl` &name=`{"name":{"0":"Simpson, Homer","1":"Simpson, Marge","2":"Simpson, Lisa","3":"Simpson, Bart"},"phone":"1-555-123-4567,1-555-123-4567,,"}`]]
         * 
         * JSON: Using &loop WITH &ph AND &json=`1` (the alternative JSON-style arrays):
         * - one placeholder only: [[Loop? &tpl=`loopTpl` &json=`1` &ph=`firstname` &loop=`Sue,Joe,Mary,Bo`]]
         * - multiple placeholders (JSON seems to need numbers starting from zero to signify multiple arrays): 
         *     [[Loop? &tpl=`loopTpl` &json=`1` &ph=`firstname,lastname` &loop=`{"0":"Sue,Mary,Bilbo,Gandalf","1":"Smith,Brown,Baggins,Grey"}`]]
         *
         * Example using &numbers: [[!Loop? &tpl=`loopTpl` &ph=`name,number` &numbers=`1` &min=`3` &max=`0` &step=`-1` &loop=`Mary==Joe==Brian` &separator=`<br />`]]
         *
         *
         * USES
         * 
         * Great for generating complex FormIt, Register, and other custom forms with multiple option, text, or other fields. 
         * Call cached in the formit report to automatically output a list of form fields: [[Loop? &tpl=`formitReportRow` &ph=`name` &loop=`name==email==phone==message`]]
         * The formitReportRow chunk: <div>[[+name:ucwords]]: <strong>[[+[[+name]]]]</strong></div>
         * 
         * It's also useful for just about any other simple repetition need where using a custom snippet is overkill.
         * Can easily be combined with other snippets (put them in the template chunks or use them to generate parameters).
         * 
         */
        require_once ($modx->getOption('core_path').'components/loop/functions.inc.php');
        $numbers = (bool)$modx->getOption('numbers',$scriptProperties,0);
        $min = $modx->getOption('min',$scriptProperties,0);
        $max = $modx->getOption('max',$scriptProperties,3);
        $step = $modx->getOption('step',$scriptProperties,1);
        
        $loop = $modx->getOption('loop',$scriptProperties,'');
        $static = $modx->getOption('static',$scriptProperties,'');
        if (empty($loop)) {$numbers = 1;}
        
        /* set placeholder options */
        $ph = $modx->getOption('ph',$scriptProperties,'');
        if (empty($ph)) {$ph = $modx->getOption('placeholder',$scriptProperties,'');}
        if (empty($ph)) {$ph = $modx->getOption('placeholders',$scriptProperties,'');}
        if (empty($ph)) {$ph = $modx->getOption('phSimple',$scriptProperties,'');}
        
        /* set whether to enable JSON (instead of MODx) style arrays */
        $json = $modx->getOption('json',$scriptProperties,0);
        if ($json) {$phSimple = 0;} else {$phSimple = 1;}
        
        /* set templating options */
        $tpl = $modx->getOption('tpl',$scriptProperties,''); 
        if (empty($tpl)) {$tpl = $modx->getOption('template',$scriptProperties,'');}
        $separator = $modx->getOption('separator',$scriptProperties,"\n");
        if (!$tpl) {$separatorInner = $modx->getOption('separatorInner',$scriptProperties," ");}
        if (!$separatorInner) {$separatorInner = '';}
        $toPlaceholder = $modx->getOption('toPlaceholder',$scriptProperties,false);
        
        /* set miscellaneous options */
        $prefix = $modx->getOption('prefix',$scriptProperties,'loop_');
        $debug = $modx->getOption('debug',$scriptProperties,0);
        $default = $modx->getOption('default',$scriptProperties,'');
        $useIdx = $modx->getOption('idx',$scriptProperties,'idx');
        $trim = $modx->getOption('trim',$scriptProperties,1);
        
        $output = '';
        
        if ($numbers) {
          $numbersArray = array();
          $numbersArray[0] = array();
          $numDif = $max-$min;
          if($numDif>0 && $step>0) {
            for($i=$min;$i<$max;$i=$i+$step) {$numbersArray[0][] = $i;}
          } elseif($numDif<0  && $step<0) {
            for($i=$min;$i>$max;$i=$i+$step) {$numbersArray[0][] = $i;}
          } else {$modx->log(modX::LOG_LEVEL_ERROR,'[Loop] Numbers function is not properly formed. Check min, max, and step parameters.'); $numbers = 0;}
        
          if ($numbers && $loop) {$mergeNumbers = 1;}
          elseif ($numbers && !$loop) {$loop = $modx->toJSON($numbersArray);}
        }
        if (!$numbers && !$loop) {$modx->log(modX::LOG_LEVEL_ERROR,'[Loop] Neither numbers nor loop is set. Nothing to do!'); return $default;}
        
        /* make &loop into a basic array */
        if (!$phSimple)  {
          $loopTempArray = $modx->fromJSON($loop);
          if (!is_array($loopTempArray)) {
            $loopTempArray = array(0 => explodeTrim(',',$loop,$trim));
          }
        } elseif ($phSimple && empty($ph) && !empty($tpl)) {
          /* phSimple && empty($ph) - format is &loop=`placeholder==value==value||placeholder2==value==value` */
          $loopArrayOuter = explodeTrim('||',$loop,$trim); /* 0 ==> ph==value==value */
          $loopTempArray = array();
          foreach ($loopArrayOuter as $key => $value) {
            $tempHolderArray = explodeTrim('==',$value,$trim); /* 0 ==> placeholder, 1 ==> value, 2==> value */
            $tempHolder = array_shift($tempHolderArray); /* tempHolder = placeholder, tempHolderArray = 0 ==> value, 1==> value */
            $loopTempArray[$tempHolder] = $tempHolderArray; /* $loopTempArray["placeholder"] = array(0 ==> "value", 1==> "value"); */
          }
          unset($loopArrayOuter,$tempHolder,$tempHolderArray);
        } else {
          /* phSimple && !empty($ph) OR empty($tpl) - format is &loop=`value==value||value==value` */
          $loopArrayOuter = explodeTrim('||',$loop,$trim);
          $loopTempArray = array();
          foreach ($loopArrayOuter as $key => $value) {
            $loopTempArray[$key] = explodeTrim('==',$value,$trim); /* $loopTempArray[] = array(0 ==> "value", 1==> "value"); */
          }
          unset($loopArrayOuter);
        }
        if ($mergeNumbers) {$loopTempArray = array_merge($loopTempArray,$numbersArray);}
        if ($debug) {$output .= 'loopTempArray (one): '.print_r($loopTempArray,1)."<br />\n";}
        
        /* make array in the format of placeholder => valuesToLoopThrough */
        if (!empty($ph)) {
          /* placeholder in a separate array. Compbine placeholders with loopArray */
          $placeholderArray = explodeTrim(',',$ph,$trim);
          $phArray = array();
        
          /* remove numeric placeholders and replace with sequential numbers */
          $placeholderCounter = 0;
          foreach ($placeholderArray as $value) {
            if(is_numeric($value)) {
              $phArray[] = $placeholderCounter;
              $placeholderCounter++;
            } else {
              $phArray[] = $value;
            }
          }
          if ($debug) {$output .= 'phArray: '.print_r($phArray,1).'<br />';}
          
          /* make sure placeholder array and value array are the same size and that values are arrays */
          $loopCountDiff = count($phArray) - count($loopTempArray);
          if ($loopCountDiff >= 1) {
          /* There are more placeholders than values. Add empty values */
            for($i = $loopCountDiff; $i>=1; $i--) {
              $loopTempArray[] = array(0 => '');
            }
            if ($debug) {$output .= 'loopTempArray (loopCountDiff >= 1): '.print_r($loopTempArray,1).'<br />';}
          } elseif ($loopCountDiff <= -1) {
            /* There are more values than placeholders. Add sequential number placeholders. */
            for($i = $loopCountDiff; $i<=-1; $i++) {
              $phArray[] = $prefix.$placeholderCounter;
              $placeholderCounter++;
            }
            if ($debug) {$output .= 'phArray (loopCountDiff <= 1): '.print_r($phArray,1).'<br />';}
            unset($placeholderCounter);
          }
        
          /* compbine placeholders and values */
          $phArray;
          $loopTempArray = array_combine($phArray,$loopTempArray);
          if ($debug) {$output .= 'loopTempArray (with ph): '.print_r($loopTempArray,1).'<br />';}
        }
        
        /* placeholder are now definitely in array. Make sure formatting is correct (placeholder => valueArray) */
        $loopArray = array();
        $loopCount = 0;
        if ($debug) {$output .= 'loopTempArray (two): '.print_r($loopTempArray,1).'<br />';}
        foreach ($loopTempArray as $placeholder => $value) {
          $loopCount++;
          
          /* value must be an array */
          if (!is_array($value)) {
          $valueArray = explodeTrim(",",$value,$trim);
          }
          else {$valueArray = $value;}
          
          /* placeholder must be a string */
          if (is_array($placeholder)) {
            $modx->log(modX::LOG_LEVEL_ERROR,'[Loop] Placeholder "'.$placeholder.'" cannot be an array.');
            $loopArray[$prefix.$loopCount] = $valueArray;
          } elseif (is_numeric($placeholder)) {
            $loopArray[$prefix.$placeholder] = $valueArray;
          } elseif (empty($placeholder)) {
            $loopArray[$prefix.$loopCount] = $valueArray;
          } else {
            $loopArray[$placeholder] = $valueArray;
          }
        }
        if ($debug) {$output .= 'loopArray (three): '.print_r($loopArray,1).'<br />';}
        
        /* rearrange array to make final looping array */
        $loopArrayFinal = array();
        $loopValueCount = array();
        foreach ($loopArray as $placeholder => $valueArray) {
          $loopValueCount[$placeholder] = count($valueArray);
        }
        $loopMaxCount = max($loopValueCount);
        if ($debug) {$output .= 'max($loopValueCount): '.$loopMaxCount.'<br />';}
        $idx = 0;
        for($i=$loopMaxCount;$i>0;$i--) {
          $loopArrayFinal[$idx] = array();
          if (!empty($useIdx)) {
            $loopArrayFinal[$idx][$useIdx] = $idx + 1;
          }
          foreach ($loopArray as $placeholder => $valueArray) {
            if (isset($valueArray[$idx])) {
              $loopArrayFinal[$idx][$placeholder] = $valueArray[$idx];
            } else {
              $loopArrayFinal[$idx][$placeholder] = '';
            }
          }
          $idx++;
        }
        
        if (count($loopArrayFinal) == 0) {$modx->log(modX::LOG_LEVEL_ERROR,'[Loop] returned no results.'); return $default;}
        if ($debug) {$output .= 'loopArrayFinal: '.print_r($loopArrayFinal,1).'<br />';}
        
        /* Loop through loopArrayFinal to produce templated output */
        $idx = 0;
        if ($phSimple) {
          $staticOuter = explodeTrim('||',$static,$trim);
          $staticArray = array();
          foreach ($staticOuter as $value) {
            $tempStaticArray = explodeTrim('==',$value,$trim);
            $staticArray[$tempStaticArray[0]] = $tempStaticArray[1];
          }
          unset($staticOuter,$tempStaticArray);
        } else {
          $staticArray = $modx->fromJSON($static);
        }
        foreach ($loopArrayFinal as $placeholder => $valueArray) {
          if ($idx > 0) {$output .= $separator;}
          $idx++;
          $valueArray = array_merge($staticArray,$valueArray);
          if (!empty($tpl)) {
            /* if template chunk is given, add chunk with placeholders to output */
            $output .= $modx->getChunk($tpl,$valueArray);
          } else {
            /* else, just separate values with separator */
            $output .= implode($valueArray,$separatorInner);
          }
        }
        if (!empty($toPlaceholder)) {
            $modx->setPlaceholder($toPlaceholder,$output);
            return '';
        } else return $output;

          WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area
          • 34022 ☆ A M B ☆
          • 91 Posts
          Added to repository.
            WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area