We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 1932
    • 137 Posts
    Below is an updated version of the required management module:

    @MODULE

    The module will automatically create the needed database table when it is first run. The default table name is: prefix_favorite_links

    Module name: Favorite Links
    Description: Management for favorite links snippet

    //<?php
    /**
    * Favorite Links Module
    * Brian Stanback
    * 2007/04/12
    * Version 0.0.5
    * Compatible with MODx 0.9.5
    *
    * Loosely Based off of Friends List Module by Garry Nutting
    */
    
    $_lang['action_title'] = 'Links Listing';
    $_lang['add_link'] = 'Add Link';
    $_lang['cancel'] = 'Cancel';
    $_lang['delete'] = 'Delete';
    $_lang['edit'] = 'Edit';
    $_lang['error_unfilled'] = 'Please fill all required fields';
    $_lang['form_message'] = '<p>To add a new link, enter link details in the form on the left and click the "Add Link" button. Tags should be separated by a comma and a space, eg. tag1, tag2, tag3. For an explanation and more information on XFN, please visit <a href="http://gmpg.org/xfn/">http://gmpg.org/xfn/</a></p><br /><p>To update a link select the link from the list, click the \'Edit\' button, and update the details in the form on the left.</p><br /><p>To remove a link select the link from the list and click the \'Delete\' button.</p>';
    $_lang['form_title'] = 'Add/Update a Link';
    $_lang['favlinks_title'] = 'Title';
    $_lang['favlinks_url'] = 'URL';
    $_lang['favlinks_summ'] = 'Summary';
    $_lang['favlinks_rating'] = 'Rating';
    $_lang['favlinks_tags'] = 'Tags';
    $_lang['favlinks_xfn'] = 'XFN';
    $_lang['filter'] = 'Filter';
    $_lang['go'] = 'Go';
    $_lang['link_added'] = 'The link has been added.';
    $_lang['link_deleted'] = 'The link has been deleted.';
    $_lang['link_updated'] = 'The link has been updated.';
    $_lang['module_title'] = 'Favorite Links';
    $_lang['no_records'] = 'No links have been added.';
    $_lang['update_link'] = 'Update Link';
    
    $basePath = $modx->config['base_path'];
    $siteURL = $modx->config['site_url'];
    $tb_prefix = $modx->db->config['table_prefix'];
    
    // Include grid control class
    include_once($basePath . 'manager/includes/controls/datagrid.class.php');
    
    // Get configuration values
    global $manager_theme;
    $table = $modx->getFullTableName('favorite_links');
    
    // Handle request data
    $link_id = (isset($_POST['link_id'])) ? intval($_POST['link_id']) : '';
    $title = (isset($_POST['title'])) ? $_POST['title'] : '';
    $url = (isset($_POST['url']) && $_POST['url'] != 'http://') ? $_POST['url'] : 'http://';
    $summ = (isset($_POST['summ'])) ? $_POST['summ'] : '';
    $tags = (isset($_POST['tags'])) ? $_POST['tags'] : '';
    $xfn = (isset($_POST['xfn'])) ? $_POST['xfn'] : '';
    $rating = (isset($_POST['rating'])) ? $_POST['rating'] : '';
    
    // Determine what action to take
    if (isset($_POST['edit']) && $link_id > 0)
    {
    	$action = 'edit';
    }
    elseif (isset($_POST['delete']) && $link_id > 0)
    {
    	$action = 'delete';
    }
    elseif (isset($_POST['action']))
    {
    	$action = $_POST['action'];
    }
    
    // Check for required fields
    if (($action == 'add' || $action == 'update') && (!$title || !$url))
    	$error = $_lang['error_unfilled'] . ' (*)';
    
    if ($action == 'update' && !isset($error))
    {
    	$tags = ':' . str_replace(', ', ':', $tags) . ':';
    
    	$fields = array(
    		'title' => $modx->db->escape($title),
    		'url' => $modx->db->escape($url),
    		'summ' => $modx->db->escape($summ),
    		'tags' => $modx->db->escape($tags),
    		'xfn' => $modx->db->escape($xfn),
    		'rating' => $modx->db->escape($rating)
    	);
    
    	$modx->db->update($fields, $table, 'id=' . $link_id);
    	$msg .= $_lang['link_updated'];
    	$link_id = ''; $title = ''; $url = 'http://'; $summ = ''; $tags = ''; $xfn = ''; $rating = '';
    }
    elseif ($action == 'delete')
    {
    	$modx->db->delete($table, 'id=' . $link_id);
    	$msg .= $_lang['link_deleted'];
    	$link_id = '';
    }
    elseif ($action == 'add' && !isset($error))
    {
    	$tags = ':' . str_replace(', ', ':', $tags) . ':';
    
    	$fields = array(
    		'title' => $modx->db->escape($title),
    		'url' => $modx->db->escape($url),
    		'summ' => $modx->db->escape($summ),
    		'tags' => $modx->db->escape($tags),
    		'xfn' => $modx->db->escape($xfn),
    		'rating' => $modx->db->escape($rating),
    		'added' => time()
    	);
    
    	$modx->db->insert($fields, $table);
    	$msg .= $_lang['link_added'];
    	$link_id = ''; $title = ''; $url = 'http://'; $summ = ''; $tags = ''; $xfn = ''; $rating = '';
    }
    
    if ($action == 'edit')
    {
    	$result = $modx->db->select('*', $table, 'id="' . $link_id . '"');
    	$row = $modx->db->getRow($result);
    	$title = $row['title'];
    	$url = $row['url'];
    	$summ = $row['summ'];
    	$tags = str_replace(':', ', ', trim($row['tags'], ':'));
    	$xfn = $row['xfn'];
    	$rating = $row['rating'];
    }
    
    if (!function_exists('checkLinksTable'))
    {
    	/**
    	* Create the table if it does not exist
    	*/
    	function checkLinksTable($table, &$errorMsg)
    	{
    		global $modx;
    
    		$sql = "CREATE TABLE IF NOT EXISTS " . $table . " (" .
    			"`id` int(11) NOT NULL auto_increment PRIMARY KEY, " .
    			"`title` varchar(255)  NOT NULL, " .
    			"`url` varchar(255) NOT NULL, " .
    			"`summ` text, " .
    			"`tags` varchar(255), " .
    			"`rating` float(2), " .
    			"`xfn` varchar(64), " .
    			"`added` char(10)" .
    		")";
    
    		if (!$modx->db->query($sql))
    			$errorMsg .= "<p class=\"error\">Error creating table {$table}!</p>\n";
    	}
    }
    
    checkLinksTable($table, $errorMsg);
    
    $filter = "";
    if ($_POST['filter'])
    {
    	$q = $modx->db->escape($_POST['filter']);
    	$filter .= "(url LIKE '%$q%' OR title LIKE '%$q%' OR summ LIKE '%$q%')";
    }
    if ($_POST['tag'])
    {
    	$q = $modx->db->escape($_POST['tag']);
    	if ($filter != "") $filter .= " AND ";
    	$filter .= "(tags LIKE '%:$q:%')";
    }
    
    $linksQuery = $modx->db->select('*', $table, $filter, 'added DESC');
    
    // Page header
    $output .= '
    <html>
    <head>
        <link rel="stylesheet" type="text/css" href="media/style/' . $manager_theme . '/style.css" />
        <style type="text/css">
    	.topdiv {
    		border: 0;
    	}
    	.subdiv {
    		border: 0;
    	}
    	li {
    		list-style:none;
    	}
    	.tplbutton {
    		text-align: right;
    	}
    	#bttn .bttnheight {
    		height: 25px !important;
    		padding: 0px;
    		padding-top: 6px;
    		float: left;
    		vertical-align: middle !important;
    	}
    	ul.sortableList {
    		padding-left: 20px;
    		margin: 0px;
    		width: 300px;
    		font-family: Arial, sans-serif;
    	}
    	ul.sortableList li {
    		font-weight: bold;
    		cursor: move;
    		color: grey;
    		padding: 2px 2px;
    		margin: 2px 0px;
    		border: 1px solid #000000;
    		background-image: url("media/style/' . $manager_theme . '/images/bg/grid_hdr.gif");
    		background-repeat: repeat-x;
    	}
    	#bttn .bttnheight {
    		height: 25px !important;
    		padding: 0px; 
    		padding-top: 6px;
    		float: left;
    		vertical-align: middle !important;
    	}
    	#bttn a{
    		cursor: default !important;
    		font: icon !important;
    		color: black !important;
    		border: 0px !important;
    		padding: 5px 5px 7px 5px!important;
    		white-space: nowrap !important;
    		vertical-align: middle !important;
    		background: transparent !important;
    		text-decoration: none;
    	}
    	#bttn a:hover {
    		border: 1px solid darkgreen !important;
    		padding: 4px 4px 6px 4px !important;		
    		background-image: url("media/style/' . $manager_theme . '/images/bg/button_dn.gif") !important;
    		text-decoration: none;
    	}
    	#bttn a img {
    		vertical-align: middle !important;
    	}
    	.go a {
    		cursor: default !important;
    		font: icon !important;
    		color: black !important;
    		border: 0px !important;
    		padding: 5px 5px 7px 5px !important;
    		white-space: nowrap !important;
    		vertical-align: middle !important;
    		background: transparent;
    		text-decoration: none;
    	}
    	.go a:hover {
    		border: 1px solid darkgreen !important;
    		padding: 4px 4px 6px 4px !important;
    		background: url("media/style/' . $manager_theme . '/images/bg/button_dn.gif");
    		text-decoration: none;
    	}
    	.go a img {
    		vertical-align: middle !important;
    	}
    	.form_message {
    		font-size: 85%;
    	}
    	.gridItem, .gridAltItem {
    		font-sizE: 95%;
    	}
    	td {
    		font-size: 90%;
    	}
    	</style>
    </head>
    <body>
    	<div class="subTitle" id="bttn">
            <span class="right"><img src="media/style/' . $manager_theme . '/images/_tx_.gif" width="1" height="5"><br />' . $_lang['module_title'] . '</span>
    	<div class="bttnheight"><a id="Button5" onclick="document.location.href=\'index.php?a=106\';">
    		<img src="media/style/' . $manager_theme . '/images/icons/close.gif" alt="" /> Close Favorite Links Manager</a>
    	</div>
    	<div class="bttnheight"><a id="Button5" onclick="document.location.href=\'index.php?a=106\';">
    		<img src="media/style' . $manager_theme . '/images/icons/link_add.png" alt="" /> Import / Export</a>
    	</div>
    	<div class="stay"></div> 
    	</div>
    	<div class="sectionHeader">' . $_lang['form_title'] . '</div>
    	<div class="sectionBody">
    ';
    
    $output .= '
    	<table><tr><td style="width: 60%;" valign="top">
    	<form name="details" method="post" action="">
    		<input type="hidden" name="action" value="' . (($action == 'edit') ? 'update' : 'add') . '" />
    		<input type="hidden" name="link_id" value="' . $link_id . '" />
    		<table border="0" cellspacing="0" cellpadding="1" width="95%">
    			<tr><td>' . $_lang['favlinks_title'] . ': *  </td><td><input type="text" name="title" value="' . $title . '" style="width: 100%;" /></td></tr>
    			<tr><td>' . $_lang['favlinks_url'] . ': *  </td><td><input type="text" name="url" value="' . $url . '" style="width: 100%;" /></td></tr>
    			<tr><td valign="top">' . $_lang['favlinks_summ'] . ':  </td><td><textarea name="summ" rows="2" style="width: 100%; height: auto;">' . $summ . '</textarea></td></tr>
    			<tr><td>' . $_lang['favlinks_tags'] . ':  </td><td><input type="text" name="tags" value="' . $tags . '" style="width: 100%;" /></td></tr>
    			<tr><td>' . $_lang['favlinks_xfn'] . ':  </td><td><input type="text" name="xfn" value="' . $xfn . '" style="width: 100%;" /></td></tr>
    			<tr><td>' . $_lang['favlinks_rating'] . ':  </td><td><input type="text" name="rating" value="' . $rating . '" style="width: 100%;" /></td></tr>
    			<tr><td> </td><td><br /><input type="submit" name="postform" value="' . (($action == 'edit') ? $_lang['update_link'] : $_lang['add_link']) . '" /></td></tr>
    		</table>
    	</form>
    	</td><td valign="top" class="form_message">' . $_lang['form_message'] . '</td></tr></table>';
    
    // Output any messages or errors
    $output .= '<div>';
    $output .= '<p class="warning">' . $msg . '</p>';
    if (isset($error)) {
    	$output .= '<p class="warning">' . $error . '</p>';
    }
    $output .= '</div>';
    
    $output .= '</div>
    		<div class="sectionHeader">' . $_lang['action_title'] . '</div>
    		<div class="sectionBody">
    		<form name="links" method="post" action="">
    		<div style="float: right;">' . $_lang['filter'] . ': <select name="tag" onchange="links.submit()"><option value="">-</option>';
    
    // Get tags from database, populating array
    $result = $modx->db->select('DISTINCT tags', $table);
    $tags = array();
    while ($row = $modx->db->getRow($result))
    {
    	foreach (explode(':', trim($row['tags'], ':')) as $tag) $tags[$tag]++;
    }
    ksort($tags);
    foreach ($tags as $tag => $occurances)
    {
    	// Output tags
    	if ($tag == $_POST['tag'])
    		$output .= "<option selected=\"selected\" value=\"$tag\">$tag</option>";
    	else
    		$output .= "<option value=\"$tag\">$tag</option>";
    }
    
    $output .= '
    		</select>  <input type="text" name="filter" size="20" value="' . $_POST['filter'] . '" /> <input type="submit" value="' . $_lang['go'] . '" /></div>
    		<input type="submit" value="' . $_lang['edit'] . '" name="edit" />  
    		<input type="submit" value="' . $_lang['delete'] . '" name="delete" /><br /><br />';
    
    // Render links grid
    $grid = new DataGrid('', $linksQuery);
    $grid->noRecordMsg = $_lang['no_records'];
    $grid->cssClass = "grid";
    $grid->columnHeaderClass = "gridHeader";
    $grid->itemClass = "gridItem";
    $grid->altItemClass = "gridAltItem";
    $grid->columns = " ," . $_lang['favlinks_title'] . "," . $_lang['favlinks_url'] . "," . $_lang['favlinks_rating'];
    $grid->colTypes = "template:<input type='radio' value='[+id+]' name='link_id' />";
    $grid->colWidths = "5%,35%,35%,15%";
    $grid->fields = "template,title,url,rating";
    $output .= $grid->render();
    
    $output .= '</form>';
    $output .= '</div></body></html>';
    
    return $output;
    


    The FavoriteLinksForm snippet (which implements bookmarklet and frontend link posting) should be fully compatible with this updated version.
      • 1932
      • 137 Posts
      To create a tagcloud, start with a snippet call similar to the one below:

      <div class="links_cloud">
      	[!FavoriteLinks? &landing=`yourdocid` &dispType=`tags` &showLinks=`0` &tplOuter=`@CODE:` &tplTag=`@FILE:tpl/tagcloud.tpl` &sortTags=`tag ASC`!]
      </div>
      


      &tplOuter=`@CODE:` tells the snippet to skip the outer template
      &tplTag=`@FILE:tpl/tagcloud.tpl` tells the snippet to use the built-in tag cloud template.

      Then use css styles similar to the following for the various sizes, etc:

      /* Example links cloud
      *************************************************/
      
      .links_cloud {
              width: 450px;
              border: 1px dashed #555;
              padding: 10px;
              line-height: 1.4em;
              font-size: 1em;
      }
      
      .links_cloud a {
              white-space: nowrap;
      }
      
      .favlinks_s5 {
              font-size: 1.75em;
              font-weight: bold;
      }
      
      .favlinks_s4 {
              font-size: 1.55em;
              font-weight: bold;
      }
      
      .favlinks_s3 {
              font-size: 1.25em;
              font-weight: bold;
      }
      
      .favlinks_s2 {
              font-size: 0.95em;
      }
      
      .favlinks_s1 {
              font-size: 0.85em;
      }
      




      Pagination with Favorite Links works very similar to that of Ditto. The snippet is executed and pagination placeholders are set; the placeholders can be used anywhere after the main snippet call. Example:

      Snippet call + pagination template:
      [[FavoriteLinks? &dispType=`landing` &paginate=`1` &paginateAlwaysShowLinks=`1` &paginateSplitter=` ` &maxLinks=`10`]]
      
      <p>Showing <strong>[+start+]</strong> - <strong>[+stop+]</strong> of <strong>[+total+]</strong> Links | Page <strong>[+currentPage+]</strong> of <strong>[+totalPages+]</strong></p>
      <div id="favlinks_pages">[+previous+] [+pages+] [+next+]</div>
      


      Depending on your MODx installation and whether or not you have PHx installed as a plugin, the snippet may have to be called uncached (as shown above) with caching disabled on the document.



        • 18397
        • 3,250 Posts
        Using a basic (no parameters) call the snippet outputs the following:

            *  google sitemap and @INHERIT TV values not retrieved
            * Support/Comments for DittoCal
            * google sitemap and @INHERIT TV values not retrieved
            * Support/Comments for DittoCal
            * google sitemap and @INHERIT TV values not retrieved
            * Support/Comments for DittoCal
        


        The previous version worked fine and the module displays the numerous entries fine.
          • 1932
          • 137 Posts
          @Mark:

          That seems really strange... It works fine on my end using no parameters. I don’t see how/why it would be affecting MODx’s template variables nor why it would be outputting a DittoCal template. huh What version of MODx are you running? Can you perhaps isolate FavoriteLinks on a page+template with no other snippet calls? Also make sure you have downloaded and uploaded the required files.

          Can anyone else confirm that it’s working/breaking?
            • 18397
            • 3,250 Posts
            Those are links in my favorites but its display those two three times instead of the rest of the entries.

            I’m on MODx 0.9.5 final on a (mt) grid server. I’ve checked the uploaded files are intact and in the correct location.
              • 1932
              • 137 Posts
              @Mark,
              Ah, I get it now. I have traced the problem to an issue with pass by reference and no PHx. Please update your download files with the updated snippet in the above post.
                • 18397
                • 3,250 Posts
                Works fine now. Thanks wink
                  • 867
                  • 241 Posts
                  does this call should work ? I’m a bit lost with the outer template things. embarrassed
                  [[FavoriteLinks? &rowChunk=`links`]]

                  For the moment it does’nt take in consideration my chunk.

                  thanks.
                  (i cant wet to set up the bookmarlet part.Tried your demo. Very impressive and useful)
                    • 1932
                    • 137 Posts
                    @alchime:

                    &rowChunk has changed to &tplLink in the latest version. Changing your call to:
                    [[FavoriteLinks? &tplLink=`links`]]

                    should fix the issue.

                    &tplOuter is the html code which goes around all of the link items. So if the link template has <li>...</li>, the outer template would be responsible for displaying the <ul> and </ul>. If you don’t need an outer template, or wish to add any html code around the snippet call itself (within your document, template, or chunk), you can do so by using &tplOuter=`@CODE:`

                    The default outer template is:
                    <ul class="links_listing">
                            [+favlinks_items+]
                    </ul>
                    


                    Yes, the bookmarklet is really handy and allows one to seamlessly post new links to a blog, etc without having to leave the site they’re on (by using &successPage=`referrer`) cool
                      • 1932
                      • 137 Posts
                      I have released a new version of the snippet, 0.0.6, which can be downloaded above. Both the snippet code within the manager as well as the download files need to be updated. This version allows a custom date/time range to be set and adds control over the starting offset plus maximum number of tags/links displayed.

                      $params['startDate'] = isset($startDate) ? $startDate : null;
                       	// Return links added on or after the specified date
                      	// Example: 2007-01-03
                      	// Example: -1 Month
                      
                      $params['endDate'] = isset($endDate) ? $endDate : null;
                      	// Return results added on or before the specified date
                      
                      $params['maxLinks'] = isset($maxLinks) ? intval($maxLinks) : 100000;
                      	// Maximum number of links to display in the result
                      
                      $params['offsetLinks'] = isset($offsetLinks) ? intval($offsetLinks) : 0;
                      	// Offset for the links result
                      
                      $params['maxTags'] = isset($maxTags) ? intval($maxTags) : 100000;
                       	// Maximum number of tags to display in the result
                      
                      $params['offsetTags'] = isset($offsetTags) ? intval($offsetTags) : 0;
                      	// Offset for the tags result
                      
                      (&offset has been renamed to &offsetLinks in order to eliminate ambiguity)



                      An example case using the start date to show links added within the previous week:
                      [!FavoriteLinks &startDate=`-1 Week`!]