We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 17565
    • 8 Posts
    I’ve been using MODx for a short time and am in need of some direction. We are creating a database of quotes on our website. Currently, we have a folder in which all the quotes live (apx 450 of them). While most of them are by various Authors, we do have multiple quotes from the same author.

    I have set up two Template Variables for each quote. One, called "brandQuoteAuthor" which displays the author’s full name: "First Last". The second is "brandQuoteAuthorLastFirst" which displays the aurthor’s full name: "Last, First".

    I need to create an alphabetical list so people can drill down into the letters A | B | C… to browse a list of Author’s Last Names. In the cases where we have multiple quotes from the same author, I will need a way to display these Authors’ Last Names only once in the listing. I know someone who uses Drupal and has created something similar without having to create individual folders for "A", "B", "C"… nor did he have to create individual folders for each author.

    I’m wondering if it is possible to use Ditto to create this. I have tried different things with Ditto and not sure where to go from here. Below is what I have so far. Please help - greatly appreciated!

    [!Ditto? &parents=`66` &hiddenFields=`true` &phx=`1` &orderBy=`brandQuoteAuthorLastFirst DESC` &tpl=`BrandQuotesByAuthor` !]
    
    id 66 = the folder containing all of the quotes (loose in this folder)
    &hiddenFields = I believe this allows Ditto to evaluate the contents of my Template Variables
    &phx = not sure if I need this?
    
    &tpl CHUNK "BrandQuotesByAuthor"
    <div class="ditto_item" id="ditto_item_[+id+]">
    <span class="brand-quote"> [+brandQuoteAuthorLastFirst+]: [+pagetitle+]</span>
    </div> 


    Thanks in Advance!
    Laura
      • 22770
      • 285 Posts
      When I wanted to do something similar, I found it a lot easier to use one of the main page fields to as the ’surname’ field, and then sort by that. I used ManagerManager to rename the pagetitle field as Surname (although you could use any standard field), and then wrote a custom snippet (making use of ditto) to sort into an A-to-Z list.

      So that the top of the page had:

      A | B | C etc, each of which were linked to the relevant part of the sorted list.

      I’m happy to share the snippet if it’s of any use to you (without any guarantees of robustness).
        • 17565
        • 8 Posts
        Thank you Patrick.

        Any information you can share would be helpful.
          • 22770
          • 285 Posts
          Here’s the snippet I’ve been using. Even if it doesn’t do exactly what you want, you may be able to adapt it to your needs.

          Make a new snippet called atozList and paste in the following:

          <?php
          //This snippet lists records alphabetically, with an A to Z header of links to anchors in the text.
          //Can sort by any content field, but not by template variables.
          //Can filter by any content field or template variable.
          
          //simple use:
          //[!atozList? &parents=`6` &listTpl=`atozStaff`!]
          //Required fields: &parents and &listTpl
          //Optional fields: &sortby &alphabetHeadingSeparator &alphabetHeadingStart &alphabetHeadingEnd &filter &noResults &excludeDocuments
          
          $alphabet = range("A", "Z");
          //Sets the field to sort by. Can't currently use template variables.
          $atozSortBy = (isset($sortby)) ? stripslashes($sortby) : 'pagetitle';
          //Separate the a-to-z headings. 
          $atozAlphabetHeadingSeparator = (isset($alphabetHeadingSeparator)) ? $alphabetHeadingSeparator : ' | ';
          //a-to-z headings start
          $atozAlphabetHeadingStart = (isset($alphabetHeadingStart)) ? $alphabetHeadingStart : '<p>';
          //a-to-z headings end
          $atozAlphabetHeadingEnd = (isset($alphabetHeadingEnd)) ? $alphabetHeadingEnd : '</p>';
          //a-to-z list chunk template. Ditto template
          $atozListChunkTpl = (isset($listTpl)) ? $listTpl : '';
          //ids of subfolders whose documents will be processed.
          $parents = (isset ($parents)) ? stripslashes($parents) : '';
          //A single basic ditto filter to exclude.
          $filter = (isset ($filter)) ? stripslashes($filter) : '';
          //Message to return if no results. 
          $noResults = (isset ($noResults)) ? stripslashes($noResults) : '';
          //A list of documents or folders to exclude (folders are included by default), separated by commas
          $excludeDocuments = (isset ($excludeDocuments)) ? stripslashes($excludeDocuments) : '';
          
          //If parent folders are defined, continue. Otherwise, do nothing at all!
          if (trim($parents) != '') {
          	
          	//This is the table that contains the document information
          	$content_table = $modx->getFullTableName("site_content");
          	//This is the table that contains the values of template variables
          	$tv_content_table = $modx->getFullTableName("site_tmplvar_contentvalues");
          	//This is the table that contains the actual template variables
          	$tv_table = $modx->getFullTableName("site_tmplvars");
          	
          	if(!empty($atozSortBy)) {
          
          		if(!empty($filter)) {
          			//Find all the field names in the site_content table, so we can identify whether filter relates to a content field or a template variable.
          			$fields_result = $modx->db->query("SELECT * FROM ". $content_table);
          			$numberfields = mysql_num_fields($fields_result);
          			$content_field=FALSE;
          			for ($i=0; $i<$numberfields ; $i++ ) {
          				if(trim($filter)==mysql_field_name($fields_result, $i)){
          					$content_field=TRUE;
          				}
          			}
          			$filterArray = explode(',', $filter);
          			
          			$filterValue = $filterArray[1];
          			
          			if(trim($filterArray[2])=='1') {
          				$condition='=';
          			}elseif(trim($filterArray[2])=='2') {
          				$condition='!=';
          			}elseif(trim($filterArray[2])=='3') {
          				$condition='>=';
          			}elseif(trim($filterArray[2])=='4') {
          				$condition='<=';
          			}elseif(trim($filterArray[2])=='5') {
          				$condition='>';
          			}elseif(trim($filterArray[2])=='6') {
          				$condition='<';
          			}elseif(trim($filterArray[2])=='7') {
          				$condition=' LIKE ';
          				$filterValue='%'.$filterValue.'%';
          			}elseif(trim($filterArray[2])=='8') {
          				$condition=' NOT LIKE ';
          				$filterValue='%'.$filterValue.'%';
          			}else{
          				$condition='='; //Default to equals, to avoid errors
          			}
          			
          			$filterValue = "'".$filterValue."'";
          		}	
          	}
          	
          	//First we are going to make a list of parent folders for a MySQL WHERE
          	//split out the parent values
          	$startArray = explode(',', $parents);
          
          	//loop through each start id and concatenate to list parent folders for database query
          	$parent_folders = '';
          	$parent_folders_for_tvquery = '';
          	foreach ($startArray as $parentid) {
          		$parent_folders .= 'parent=' . $parentid . ' OR ';
          		$parent_folders_for_tvquery .= $content_table . '.parent=' . $parentid . ' OR ';
          	}
          	$parent_folders = substr($parent_folders, 0, -4);
          	$parent_folders_for_tvquery = substr($parent_folders_for_tvquery, 0, -4);
          	$parent_folders_where = '(' . $parent_folders . ')';
          
              //Now we are going to make a list of documents that will be excluded for a MySQL WHERE
          	//split out the document values
          	$startDocumentArray = explode(',', $excludeDocuments);
          
          	$exclude_documents = '';
          	$exclude_documents_for_tvquery = '';
          	$exclude_documents_where = '';
          	$exclude_documents_for_tvquery_where = '';
          	//We want to also add the individual documents to the overall ditto filter at the end
          	$ditto_filter = '';
          	if(!empty($excludeDocuments)){
          		if(!empty($filter)){
          			$ditto_filter .= $filter . '|';
          		}
          		foreach ($startDocumentArray as $documentid) {
          			$exclude_documents .= 'id!=' . $documentid . ' AND ';
          			$exclude_documents_for_tvquery .= $content_table . '.id!=' . $documentid . ' AND '; 
          			$ditto_filter .= 'id,' . $documentid . ',2|';
          		}
          		$exclude_documents = substr($exclude_documents, 0, -5);
          		$exclude_documents_for_tvquery = substr($exclude_documents_for_tvquery, 0, -5);
          		$exclude_documents_for_tvquery_where = ' AND (' . $exclude_documents_for_tvquery . ')';
          		$exclude_documents_where = ' AND (' . $exclude_documents . ')';
          		$ditto_filter = substr($ditto_filter, 0, -1);
          	} else {
          		$ditto_filter = $filter;
          	}
          	
          	//Ensure only published documents are displayed. Ensure that folders are displayed by default
          	$conditional_where = ' AND published=1 AND deleted=0 AND privateweb=0';
          
          	//Select the pagetitles to have records to count
          	$content_select = 'pagetitle';
          	
          	$documentId = $modx->documentIdentifier;
          	$alphabetHeadings = $atozAlphabetHeadingStart;
              $output = '';
              foreach($alphabet AS $value) {
          		//The where statement for the ditto call
          		$where = $atozSortBy . " LIKE '" . $value . "%'";
          		//Want to check if there are any records in the database that match, before we start the ditto call.
          		//First check if there is a filter. If so, see if the filter is on a content field or a template variable.
          		if(!empty($filter)){
          			if($content_field){
          				$full_where = $parent_folders_where . $exclude_documents_where . $conditional_where . " AND " . $where . " AND " . $filterArray[0] . $condition . $filterValue;
          				$contentResult = $modx->db->select($content_select, $content_table, $full_where, '', '');
          				$total_rows = $modx->db->getRecordCount( $contentResult );
          			} else {
          				//Query to see if there are any values of template variables that match the filter.
          				$total_rows = 0;
          				$select = $tv_content_table . ".`contentid` AS contentid";
          				$from = $tv_content_table . ", " . $tv_table . ", " . $content_table;
          				$full_where = $content_table . '.`id`=' . $tv_content_table . '.`contentid` AND ' . $tv_table . ".`id`=" . $tv_content_table . ".`tmplvarid` AND value" . $condition . $filterValue . " AND name='" . $filterArray[0] . "' AND " . $where . " AND (" . $parent_folders_for_tvquery . ")" . $exclude_documents_for_tvquery_where . $conditional_where;
          				$tvResult = $modx->db->select($select, $from, $full_where, '', '');
          				$number_rows = $modx->db->getRecordCount( $tvResult );
          				$document_where = "";
          				if($number_rows>0){
          					//If there are values of tvs that match the filter, see if there are any results that fit the appropriate A-Z
          					while($row=$modx->db->getRow($tvResult)) {
          						$document_where .= $content_table .".`id`=" . $row['contentid'] . " OR "; 
          					}
          					$document_where = substr($document_where, 0, -4);
          					$full_where = $parent_folders . $conditional_where . " AND " . $where . " AND " . $document_where;
          					$contentResult = $modx->db->select($content_select, $content_table, $full_where, '', '');
          					$total_rows = $modx->db->getRecordCount( $contentResult );
          				}
          			}
          		}else{
          			$full_where = $parent_folders_where . $exclude_documents_where .  $conditional_where . " AND " . $where;
          			$contentResult = $modx->db->select($content_select, $content_table, $full_where, '', '');
          			$total_rows = $modx->db->getRecordCount( $contentResult );
          		}
          		
          		if($total_rows > 0) {
          			//Update the A-Z link list at top of page
          			$alphabetHeadings .= '<a href="'.$modx->makeUrl($documentId).'#jump_to_' . $value . '">' . $value . '</a>';
          			$alphabetHeadings .= $atozAlphabetHeadingSeparator;
          			$output .= "<p><a name=\"jump_to_$value\" id=\"jump_to_$value\"></a><strong>" . $value . "</strong></p>";
          			$output .= $modx->runSnippet("Ditto",array("parents" => "$parents", "display" => "all", "sortBy" => "$atozSortBy", "sortDir" => "ASC", "filter" => "$ditto_filter", "tpl" => "$atozListChunkTpl", "hideFolders" => "0", "where" => "$where"));
          		} 
          	}
          	$separatorCount = strlen($atozAlphabetHeadingSeparator);
          	$alphabetHeadings = substr($alphabetHeadings, 0, -$separatorCount);
          	$alphabetHeadings .= $atozAlphabetHeadingEnd;
          	
          	if($output) {
          		$output = $alphabetHeadings . $output;
          		return $output;
          	} else {
          		return $noResults;
          	}
          }
          ?>