I have a copy of the affiliates module used on http://spreadfirefox.com . It lets you create affiliate links with specific paths and banners for your site and provides a point system for tracking user success, also a block to display recent affiliates. I've been authorized to release it to the drupal community. It just needs an update for 4.5, but that may only require a few lines for node_access issues. Should be very simple for someone not as daft as me. email me through the "contact" form on here if you are interested in using this module and updating it.
Jason

Comments

boris mann’s picture

The proper procedure is to get a CVS account and upload it -- then the entire developer community can work with it.

That being said, you still need to find someone who wants to be the maintainer if you can't do it yourself.

Perhaps contact the author of the other Affiliate module which is already 4.5-compatible (I have no idea how the features might differ).

jasonwhat’s picture

I already contacted the maintainer of that modoule. It is not updated and won't be until someone else does it, or a few months pass. I don't even know how to use CVS let alone maintain a module. The developer from Firefox said I could release it to the community, so I figured I'd ask if anyone is interested. The other Affiliate module has been sitting without any update for a few months, no need to upload this one to have it do the same.

Again, if anyone is interested let me know. It's a great module, but it would be irresponsible of me to ask for CVS to upload something I can't even update.

boris mann’s picture

Again, I ask, what is the difference between this and the current Affiliate module (which is updated to 4.5)? A description of the features (esp. vs. this other module) would be helpful in determining if someone wants to pick it up. Right now, I would just look at the already working Affiliate module, unless this other one does something better.

The best thing to do is to upload this somewhere so that people can at least see the code.

jasonwhat’s picture

If you looked at the CVS log you would realize the only update to the affiliate module is a note that it is NOT 4.5 compatible. I discussed this with the developler who agreed that it is not 4.5 compatible yet, unless he was misleading me like a certain comander in chief. If it is 4.5 compatible that is great, but what I understand from it is that the admin hands out affiliate links only to specific users. It only tracks people who use the link and become members of the site. This affiliates module allows any user with proper persmissions to have affiliate links. Whoever has permission to create the links may create them to any location on the site. There are points given to users based on that performance and there is a block for the top affiliates and the latest ones as well.

Again I would be happy to try out a 4.5 version of the affiliate module. However, this link says it isn't compatible http://cvs.drupal.org/viewcvs/drupal/contributions/modules/affiliate/rea...

Steven’s picture

Yet the module is tagged as 4.5? This is what others see on the drupal.org site, so it should be fixed. Very few people will read the readme before reading the project's version string. See:
http://drupal.org/node/11169

--
If you have a problem, please search before posting a question.

Tem Noon’s picture

I didn't write it, but I sponsored development of the other affiliate link, and it only includes URL links. I am interested in more flexibility in the link, and the current one doesn't have any link with banners. Call it Banner_Link.module or whatever you want to differentiate it in the CVS. If you can't manage it, email whatever you have to me at tem@streetbuddhism.com. Not that I've ever posted something to CVS, but I should learn.

jasonwhat’s picture


/* Drupal Affiliates Module
 * The basic functionality of this module allows admins to create buttons, banners, and links that will allow users to put said buttons, etc., on their sites and generate points for themselves by sending traffic to the site. Admins can set up different types of buttons (or text links) and specify different redirects for all of them. Different entities can also have different point values. Points are tallied in the cron script for display in the block (scalability becomes an issue fast if you get much of a user base and many clicks, so doing this on a cron can be important. Top five used banners, buttons, etc., are displayed on the user's private view of his or her account page.
 * Author: Daryl L. L. Houston (daryl@learnhouston.com)
 * Version: 0.1
 * Last Updated: Oct 3, 2004
*/

function affiliates_settings(){
	//Note that the alt and title tags should be configurable!
	$output .= form_textfield(t('Block Blurb'), 'affiliate_block_blurb', variable_get('affiliate_block_blurb','Check out these leading affiliates!'), 30, 100);
	$output .= form_textarea(t("Stats User Blurb"), "affiliate_stats_blurb", variable_get("affiliate_stats_blurb", ""), 70, 4, t("Copy and paste the source below to link to us and get affiliate credit."));
	//$output .= form_textfield(t('Stats User Blurb'), 'affiliate_stats_blurb', variable_get('affiliate_stats_blurb','Copy and paste the source below to link to us and get affiliate credit.'), 30, 100);
	$output .= form_textfield(t('Button Image Title'), 'affiliate_stats_button_title', variable_get('affiliate_stats_button_title','Get Firefox!'), 30, 100);
	return $output;
}

function get_affiliates_info($limit=NULL){
	global $user, $base_url;
	$output .= form_item(t("Affiliate Stats"), variable_get('affiliate_stats_blurb','Copy and paste the source below to link to us and get affiliate credit.'), "", array("title" => t(variable_get('affiliate_stats_button_title','Get Firefox!'), array("%username" => $user->name))));
	$result=db_query("SELECT SUM(aw.value) as my_points FROM affiliates as a, affiliates_weights as aw WHERE aw.id=a.type AND a.user_id = " . intval($user->uid));
	$row=db_fetch_object($result);
	if($user->uid > 0){
		$output .= "Your points: " . $row->my_points . "<br/>";	
	}

	//Display all active links.
	if($limit==NULL){
		$result=db_query("SELECT aw.*, ac.label as cat_name FROM affiliates_weights as aw, affiliates_cats as ac where aw.status='Active' AND aw.cat_id=ac.id ORDER BY aw.cat_id ASC, order_by ASC");
	}
	//Else display just the top $limit links. This is used on the "my account" page.
	else{
		$output .= "The top " . $limit . " most popular banners appear below. For a complete listing of available banners, click <a href=\"?q=affiliates/homepage\">here</a>.<br/><br/>";
		$result=db_query("SELECT aw.*, ac.label as cat_name, SUM(aw.value) as sums FROM affiliates_weights as aw, affiliates_cats as ac LEFT JOIN affiliates ON affiliates.type=aw.id WHERE ac.id=aw.cat_id AND status='Active' GROUP BY aw.id ORDER BY sums DESC, order_by ASC LIMIT " . intval($limit));
	}

	//Initialize a variable that we use to determine whether or not to print a category heading.
	$cat_name="";
	while($row=db_fetch_object($result)){
		//If we've sent no limit and are thus printing all links, we need to print category headings.
		if($limit==NULL){
			//If the cat_name is different, we've entered a new category and should print it.
			if($row->cat_name != $cat_name){
				$output .= "<h2>" . $row->cat_name . "</h2>";
				$cat_name=$row->cat_name;
			}
		}
		//If the type specified is an image (rather than a text link), print image so users can preview what they're going to be adding to their site.
		if($row->type=="image"){
			$output .= "<img src=\"" . t($row->anchor) . "\"/><br/>\n";
		}
		//Else, um, print text code.
		else{
			$output .= "Link Text: " . t($row->anchor) . "<br/>\n";
		}
		//Now add the textarea for copying the code. 
		$output .= "<textarea rows=\"3\" cols=\"40\"><a href=\"" . $base_url . "/?q=affiliates&amp;id=" . $user->uid . "&amp;t=" . intval($row->id) . "\">";
		if($row->type=="image"){
			$output .= "<img border=\"0\" alt=\"" . variable_get('affiliate_stats_button_title',$base_url) . "\" title=\"" . variable_get('affiliate_stats_button_title',$base_url) . "\" src=\"" . $row->anchor . "\"/>";
		}
		else{
			$output .= t($row->anchor);
		}
		$output .= "</a></textarea><br/>\n";
		//Now add the label assigned through the admin interface.
		$output .= t($row->label) . ": " . t($row->value) . "<br/><br/><br/>\n";	
	}
	return $output;
}

function affiliates_help($section) {
	switch ($section) {
		case 'admin/system/modules#description':
			// This description is shown in the listing at admin/modules.
			return t('A module that allows affiliate click-throughs to be tracked.');
		case 'node/add#affiliates':
			// This description shows up when users click "create content."
			return t('Set affiliate types and values below.');
	}
}

/**
 * Implementation of hook_node_name().
 *
 * This is a required node hook. Since our module only defines one node
 * type, we won't implement hook_node_types(), and our hook_node_name()
 * implementation simply returns the translated name of the node type.
 */
function affiliates_node_name($node) {
	return t('affiliates');
}

/**
 * Implementation of hook_access().
 *
 * Every node module must implement node_access() to determine the operations
 * users may perform on nodes. This example uses a very common access pattern.
 */
function affiliates_access($op, $node) {
	if ($op == 'view'){
		// Allow a user to view the node if its status is "published."
		return $node->status;
	}

	if ($op == 'admin') {
		// Only users with permission to do so may create this node type.
		return user_access('admin affiliate');
	}
}

/**
 * Implementation of hook_perm().
 *
 * Since we are limiting the ability to create new nodes to certain users,
 * we need to define what those permissions are here. We also define a permission
 * to allow users to edit the nodes they created.
 */
function affiliates_perm() {
	return array('administer affiliates', 'view own affiliate stats', 'affiliate click');
}


function affiliates_admin(){
	global $error;
	$op = $_POST["op"];
	$edit = $_POST["edit"];
                                                                                                                       
	$id = arg(5);
                                                                                                                       
	if (empty($op) || $op == t('Submit')) {
		$op = arg(4);
	}
                                                                                                                       
	switch ($op) {
		//Adding new type.
		case "add":
			//Do the insert.
			if ($edit["edit"]=="add") {
				if($edit["new_affiliate_type_points"] != "" && $edit["new_affiliate_type_label"] != ""){
					db_query("INSERT INTO affiliates_weights VALUES(NULL,'%s','%d','%s','%s','%s','%d','%s','%s')",$edit["new_affiliate_type_label"],$edit["new_affiliate_type_points"],$edit["new_affiliate_type_anchor"],$edit["new_affiliate_type_type"],$edit["new_affiliate_type_cat"],$edit["new_affiliate_type_orderby"],$edit["new_affiliate_type_redirect"],"Active");
				}
				drupal_set_message("Affiliate link added.");
				$output=affiliates_form($node,$error,"edit_types");
			}
			//Show the form.
			else{
				$output=affiliates_form($node,$error,"new_type");
			}
			break;
		//Editing existing type.
		case "edit":
			//Do the update.
			if ($edit["edit"]=="update") {
				$result=db_query("SELECT aw.*, ac.label as cat_name FROM affiliates_weights as aw, affiliates_cats as ac WHERE ac.id=aw.cat_id AND status='Active' ORDER BY order_by ASC");
				while($type=db_fetch_object($result)){
					$key="affiliate" . $type->id;
					db_query("UPDATE affiliates_weights SET order_by='" . $edit[$key . "_orderby"] . "', label='" . $edit[$key . "_label"] . "', value='" . $edit[$key . "_value"]  . "', anchor='" . $edit[$key . "_anchor"] . "', type='" . $edit[$key . "_type"] . "', redirect='" . $edit[$key . "_redirect"] . "', cat_id='" . $edit[$key . "_cat"] . "', status='" . $edit[$key . "_status"] . "' WHERE id=" . intval($type->id));
				}
				drupal_set_message("Affiliate link updated.");
				$output=affiliates_settings();
			}
			//Show the form.
			else{
				$output=affiliates_form($node,$error,"edit");
			}
			break;
		default:
	}
	print theme("page", $output);
}


function affiliates_link($type, $node = 0, $main) {
	$links = array();
	if($type=="system" && user_access("administer affiliates")){
    	menu("admin/system/modules/affiliates", "affiliates", "affiliates_admin");
    	menu("admin/system/modules/affiliates/add", "add type", "affiliates_admin");
    	menu("admin/system/modules/affiliates/edit", "edit types", "affiliates_admin");
	}
	if ($type == 'node' && $node->type == 'affiliates'){
		menu("affiliates", "affiliates", "affiliates_view");
		$links[] = l(t('view affiliate link'), "node/$node->nid/view");
	}
	if (user_access("access content")) {
		menu("affiliates", t("affiliates"), "affiliates_view", 0, MENU_HIDE);
		menu("affiliates/homepage", t("affiliates homepage"), "affiliates_homepage", 0, MENU_HIDE);
	}
	menu("affiliates/homepage", t("affiliates homepage"), "affiliates_homepage", 0, MENU_HIDE);
	menu("affiliates/homepage2", t("affiliates homepage"), "affiliates_homepage2", 0, MENU_HIDE);
	menu("affiliates/top250", t("Roll Call Top 250"), "affiliates_top250", 0, MENU_HIDE);
	return $links;
}

/**
 * Implementation of hook_menu().
 *
 * In order for users to be able to add nodes of their own, we need to
 * give them a link to the node composition form here.
 */
function affiliates_menu() {
	$items = array();
	$items[] = array('path' => 'node/add/affiliates', 'title' => t('affiliates'),
		'access' => user_access('admin affiliates'));
	return $items;
}

/**
 * Implementation of hook_form().
 *
 * Now it's time to describe the form for collecting the information
 * specific to this node type. This hook requires us to return some HTML
 * that will be later placed inside the form.
 */
function affiliates_form(&$node, &$error, $param="default") {
	//$output = '';

	//Display the form for adding new types.
	if($param=="new_type"){
		$output .= form_textfield(t('Label'), 'new_affiliate_type_label', "", 30, 30);
		$output .= form_textfield(t('Weight'), 'new_affiliate_type_points', "", 3, 3);
		$output .= "<span class=\"form-text\">" . t('Type: ') . "</span> <select name=\"edit[new_affiliate_type_image]\">\n<option value=\"image\">Image</option>\n<option value=\"text\">Text</option>\n</select>\n<br /><br />\n";
		
		$output .= "<span class=\"form-text\">" . t('Category: ') . "</span> <select name=\"edit[new_affiliate_type_cat]\">\n";
		$result=db_query("SELECT id, label FROM affiliates_cats WHERE active='Y' ORDER BY label ASC");
		while($row=db_fetch_object($result)){
			$output .= "\t<option value=\"" . $row->id . "\"" . (($type["cat_id"]==$row->id)?" selected=\"true\"":"") . ">" . $row->label . "</option>\n";
		}
		$output .= "</select><br /><br />\n";
		$output .= form_textfield(t('Anchor'), 'new_affiliate_type_anchor', "", 40,120);
		$output .= form_textfield(t('Redirect'), 'new_affiliate_type_redirect', "", 40,80);
		$output .= form_textfield(t('Order'), 'new_affiliate_type_orderby', "", 10,5);
		$output .= form_hidden("edit","add");
		$output .= form_submit(t("Submit"));
	}
	//Display the form for editing existing types.
	else{
		$categories=array();
		$result=db_query("SELECT id, label FROM affiliates_cats WHERE active='Y' ORDER BY label ASC");
		while($row=db_fetch_object($result)){
			$categories[$row->id]=$row->label;
		}
		$result=db_query("SELECT aw.*, ac.label as cat_name FROM affiliates_weights as aw, affiliates_cats as ac WHERE ac.id=aw.cat_id AND status='Active' ORDER BY order_by ASC");
		while($type=db_fetch_object($result)){
			if($type->label != ""){
				$output .= "<span class=\"form-text\">" . t('Label: ') . "</span> <input type=\"text\" name=\"edit[affiliate" . $type->id . "_label]\" value=\"" . t($type->label) . "\" size=\"30\" maxlength=\"30\"><br/>\n";
				$output .= "<span class=\"form-text\">" . t('Weight: ') . "</span> <input type=\"text\" name=\"edit[affiliate" . $type->id . "_value]\" value=\"" . t($type->value) . "\" size=\"4\" maxlength=\"4\"><br/>\n";
				$output .= "<span class=\"form-text\">" . t('Type: ') . "</span> <select name=\"edit[affiliate" . $type->id . "_type]\">\n";
				$output .= "\t<option value=\"image\"" . (($type->type=="image")?" selected=\"true\"":"") . ">Image</option>\n";
				$output .= "\t<option value=\"text\"" . (($type->type=="text")?" selected=\"true\"":"") . ">Text</option>\n";
				$output .= "</select><br/>\n";
				$output .= "<span class=\"form-text\">" . t('Category: ') . "</span> <select name=\"edit[affiliate" . $type->id . "_cat]\">\n";
				foreach($categories as $id => $label){
					$output .= "\t<option value=\"" . $id . "\"" . (($type->cat_id==$id)?" selected=\"true\"":"") . ">" . $label . "</option>\n";
				}
				reset($categories);
				$output .= "</select><br/>\n";
				$output .= "<span class=\"form-text\">" . t('Anchor: ') . "</span> <input type=\"text\" name=\"edit[affiliate" . $type->id . "_anchor]\" value=\"" . t($type->anchor) . "\" size=\"40\" maxlength=\"120\"><br/>\n";
				$output .= "<span class=\"form-text\">" . t('Redirect: ') . "</span> <input type=\"text\" name=\"edit[affiliate" . $type->id . "_redirect]\" value=\"" . t($type->redirect) . "\" size=\"40\" maxlength=\"80\"><br/>\n";
				$output .= "<span class=\"form-text\">" . t('Order: ') . "</span> <input type=\"text\" name=\"edit[affiliate" . $type->id . "_orderby]\" value=\"" . t($type->order_by) . "\" size=\"10\" maxlength=\"5\"><br/>\n";
				$output .= "<span class=\"form-text\">" . t('Status: ') . "</span> <select name=\"edit[affiliate" . $type->id . "_status]\">\n";
				$output .= "\t<option value=\"Active\"" . (($type->status=="Active")?" selected=\"true\"":"") . ">Active</option>\n";
				$output .= "\t<option value=\"Inactive\"" . (($type->status=="Inactive")?" selected=\"true\"":"") . ">Inactive</option>\n";
				$output .= "\t<option value=\"Hidden\"" . (($type->status=="Hidden")?" selected=\"true\"":"") . ">Hidden</option>\n";
				$output .= "</select><br/><br/><br/>\n";
			}
		}
		$output .= form_hidden("edit","update");
		$output .= form_submit(t("Submit"));
	}
	return form($output);
}

/**
 * Implementation of hook_validate().
 *
 */
function affiliates_validate(&$node) {
	return;
}

/**
 * Implementation of hook_content().
 *
 * This is a typical implementation that simply runs the node text through
 * the output filters.
 */
function affiliates_content($node, $teaser = FALSE) {
	//$node->body .= 'test';
	//$node->teaser .= 'teaser';
	$node->body .= 'test';
	$node->teaser .= 'test';
	return node_prepare($node, $teaser);
}

function affiliates_user($type, &$edit, &$user) {
	global $base_url;
	switch ($type) {
		//Show how many points another user has.
		case "view_public":
			$result=db_query("SELECT SUM(aw.value) as my_points FROM affiliates as a, affiliates_weights as aw WHERE aw.id=a.type AND a.user_id =" . intval($user->uid));
			$row=db_fetch_object($result);
			
			$output = $user->name . " has earned " . number_format($row->my_points) . " points.<br /><br />";
			$output = form_item(t("Roll Call Stats"), t($output), "", array("title" => t(variable_get('affiliate_stats_button_title','Get Firefox!'), array("%username" => $user->name))));
			break;
		//View the top five banners/buttons.
		case "view_private":
			if (user_access("view own affiliate stats", $user)) {
				$output .= get_affiliates_info(5);
			}
	}
	return $output;
}


function affiliates_homepage(){
	echo theme('page', get_affiliates_info());
}

//Sorry, I know this is sloppy. Needed one that returned rather than printed as a quick and dirty fix to a modified profile page.
function affiliates_homepage2(){
	return get_affiliates_info(5);
}

function affiliates_top250(){
	//This is generated in affiliates_cron() because it stands to be a pretty beefy query and won't scale otherwise.
	$output .= variable_get("affiliates_top_250");
	echo theme('page', $output);

}

function affiliates_cron(){
	//This could probably be done better (especially from a template standpoint), but I was in a rush to move stuff into this cron function for scalability's sake.
        $users=array();
	$user_ids=array();
        $output=$homeoutput="<table>\n";
	//Get the top 250 point values and the user_ids they go with and stick them in an array.
        $result=db_query("SELECT a.user_id, SUM(aw.value) as leader from affiliates as a, affiliates_weights as aw WHERE aw.id=a.type AND a.user_id != 0 GROUP BY a.user_id ORDER BY leader DESC limit 250");
        while($row=db_fetch_object($result)){
                $users["s_" . intval($row->user_id)]=array("id"=>$row->user_id,"clicks"=>$row->leader);
		array_push($user_ids,$row->user_id);
        }
	//Running a second query here because we can execute this on a subset of the overall userbase (only the relevant ones rather than, in the case of the site this was originally built for, thousands and thousands of users, which was a pretty crippling query: When the large users table was joined to the larger affiliates table as in the original code, the server couldn't handle the load (especially as it was done on every page load rather than on a schedule).
        $result=db_query("SELECT uid, name, data FROM users WHERE uid IN (" . join(',',$user_ids) . ")");
        while($row=db_fetch_object($result)){
                $users["s_" . intval($row->uid)]["name"]=$row->name;
                $users["s_" . intval($row->uid)]["data"]=unserialize($row->data);
                $users["s_" . intval($row->uid)]["homepage"]=$users["s_" . intval($row->uid)]["data"]["profile_homepage"];
                if($users["s_" . intval($row->uid)]["homepage"]){
                        $users["s_" . intval($row->uid)]["name"]="<a href=\"" . $users["s_" . intval($row->uid)]["homepage"] . "\">" . $users["s_" . intval($row->uid)]["name"] . "</a>";
                }
        }
	$homecount=1;
        foreach($users as $u){
		//If we're in the top ten, add to a variable for the home page block. In any case, add to a variable used to print the top 250 page in affiliates_top250().
		if($homecount <= 10){
                	$homeoutput .= "\t<tr>\n\t\t<td><b>" . number_format($u["clicks"]) . "</b></td>\n\t\t<td>" . $u["name"] . "</td>\n\t\t<td><a href=\"?q=user/view/" . intval($u["id"]) . "\">sfx page</a></td></tr>\n";
		}
                $output .= "\t<tr>\n\t\t\n\t\t<td>" . $homecount . "</td><td><b>" . number_format($u["clicks"]) . "</b></td>\n\t\t<td>" . $u["name"] . "</td>\n\t\t<td><a href=\"?q=user/view/" . intval($u["id"]) . "\">sfx page</a></td></tr>\n";
		$homecount++;
        }
        $output .= "</table>\n";
        $homeoutput .= "</table>\n";
        variable_set("affiliates_top_ten",$homeoutput);
        variable_set("affiliates_top_250",$output);
}


/**
 * Implementation of hook_view().
 *
 * This is the redirect page, and the function is called when somebody clicks the link generated for a given button. It does some cookie and IP mojo to try to discourage cheating, logs the hit if it seems a valid (non-cheating) hit, and redirects to the URL specified for the button in question. 
 * 
 * 
 */

function affiliates_view(&$node, $teaser = FALSE, $page = FALSE) {
	global $base_url;
	$new_cookie=md5(microtime());
	$stored_cookie=$_COOKIE["aff"];
	$flag=1;

	//Awful hack to get around &amp; in URLs to allow redirect. PHP INI settings didn't seem to work and I had users not getting their redirect credit.
	if(!$_GET["t"]){ $_GET["t"]=$_GET["amp;t"]; }
	if(!$_GET["id"]){ $_GET["id"]=$_GET["amp;id"]; }

	//Timeout allows one click per IP per day. Hope there aren't too many people going over a proxy.
	$timeout_query="SELECT count(*) as cnt FROM affiliates WHERE ip='" . getenv('REMOTE_ADDR') . "' AND UNIX_TIMESTAMP(NOW()) < (click_time + 86400)";

	//If there's no cookie, proceed.
	if($stored_cookie=="" || !$stored_cookie){
		setcookie("aff",$new_cookie,time() + 86400);
		$result=db_query($timeout_query);
		$row=db_fetch_object($result);
		if($row->cnt > 0){
			$flag=true;
		}	
		else{
			$flag=false;
		}
	}
	//Yes, this is duplicate code. Have to run this check whether or not there's a cookie, so it's in both spots. Could be rearranged, but screw it; I'm in a hurry.
	else{
		$result=db_query($timeout_query);
		$row=db_fetch_object($result);
		if($row->cnt > 0){
			$flag=true;
		}	
		else{
			$flag=false;
		}
	}
	//Only log the hit if it looks like this isn't a cheater.
	if($flag==false){
		db_query("INSERT INTO affiliates VALUES(NULL,'" . $_GET["id"] . "','" . $cookie . "','" . getenv('REMOTE_ADDR') . "','" . getenv('HTTP_REFERER') . "','" . $_GET["t"] . "',UNIX_TIMESTAMP(NOW()))");
	}
	$results=db_query("SELECT redirect FROM affiliates_weights WHERE id=" . intval($_GET["t"]));
	$row=db_fetch_object($results);

	//Just in case there's not a redirect defined...
	if(!$row->redirect){
		$row->redirect=$base_url;
	}
	header("Location: " . $row->redirect);
}

function affiliates_block($op = 'list', $delta = 0){
	global $user;

	if ($op == "list") {
		$block[0]["info"] = t("Affiliates");
		return $block;
	}
	else{
		//Originally, this did a big honking query for every page load to calculate and display the top affiliates. This brought a pretty robust server to its knees once there were more than just a few hundred users and a fair amount of traffic. So now we crunch the stats in the cron script and retrieve it here for display.
		$output .= variable_get('affiliate_block_blurb','Check out these leading affiliates!') . "<br/><br/>";
		$output .= variable_get('affiliates_top_ten','no data');	
		$output .= "<br /><a href=\"?q=affiliates/top250\">more &gt;&gt;</a>";

		//If a valid user, go ahead and grab his or her points. This is a pretty minor operation that it doesn't seem to hurt to run every time.	
		if($user->uid > 0){
			$result=db_query("SELECT SUM(aw.value) as my_points FROM affiliates as a, affiliates_weights as aw WHERE a.user_id=" . intval($user->uid) . " AND aw.id=a.type LIMIT 1");
			$row=db_fetch_object($result);
			if($row->my_points == ''){
				$row->my_points=0;
			}
			$output .= "<br/><br/>You've accumulated " . $row->my_points . " points.";
		}	

		$block["content"] = $output;
		$block["subject"] = t("Roll Call");
    		return $block;
	}
}

and this is the SQL

CREATE TABLE `affiliates` (
`id` int(10) unsigned zerofill NOT NULL auto_increment,
`user_id` int(10) unsigned zerofill default NULL,
`cookie_id` varchar(56) default NULL,
`ip` varchar(15) default NULL,
`referer` varchar(80) default NULL,
`type` int(3) unsigned zerofill default NULL,
`click_time` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `cookie_id` (`cookie_id`),
KEY `ip` (`ip`),
KEY `click_time` (`click_time`)
) TYPE=MyISAM;

CREATE TABLE `affiliates_weights` (
`id` int(10) unsigned zerofill NOT NULL auto_increment,
`label` varchar(30) default NULL,
`value` int(4) default NULL,
`anchor` varchar(100) default NULL,
`type` enum('image','text') default NULL,
`cat_id` int(3) unsigned zerofill default NULL,
`order_by` int(5) default NULL,
`redirect` varchar(100) default NULL,
`status` enum('Active','Inactive','Hidden') default NULL,
PRIMARY KEY (`id`),
KEY `type` (`type`),
KEY `cat_id` (`cat_id`),
KEY `status` (`status`)
) TYPE=MyISAM;

CREATE TABLE `affiliates_cats` (
`id` int(3) unsigned zerofill NOT NULL auto_increment,
`label` varchar(30) default NULL,
`active` enum('Y','N') default NULL,
PRIMARY KEY (`id`)
) TYPE=MyISAM;

INSERT INTO affiliates_cats VALUES(NULL,'Email Signature','Y');
INSERT INTO affiliates_cats VALUES(NULL,'Buttons','Y');
INSERT INTO affiliates_cats VALUES(NULL,'Ad Banners','Y');

I know line 186 causes a fatal error. Please share if anyone is able to fix or interested. Also if anyone wants to own it on CVS have at it.

ericatkins’s picture

Can we see an example page? Link?

jasonwhat’s picture

http://www.spreadfirefox.com/?q=affiliates/homepage
It is basically like this page, but each user also has their own affiliate links and can be given points for their click-throughs. Notice the listing of top affilaliates on the right of the page.


Help get Tsunami survivors back to school

Poolio’s picture

just curious if there's been any more work done on getting this to work with 4.5.x

Put your money where your mouth is!

jasonwhat’s picture

I shopped it around and nobody seemed interested.
Only local images are allowed.

$5 USD can send a survivor back to school

budda’s picture

Just to let people know, i'm having a look at this module with regards to changing it for Drupal 4.5.2 compatibility.

So far, some text and the menus have needed attention. Will post back here when its done and ready for use.

--
www.bargainspy.co.uk | www.spamfo.co.uk | www.buddasworld.co.uk

Poolio’s picture

I'm looking forward to the day when this is 4.5.2 compatible (and I'm sure I'm not alone).

Put your money where your mouth is!

mediamotor’s picture

Thanks budda!

We greatly appreciate your effort!

pruner’s picture

just wondering if you've made any progress in terms of getting it working for 4.5.2?

Poolio’s picture

I'd really like for this module to work (with 4.5.2), and would even be willing to pay (or chip in) if that's what it would take.

Put your money where your mouth is!

Frando’s picture

... I'm very very interested, too... would really be great if you'd make it running under 4.6

budda’s picture

Hi,

After many emails i thought i should just post a message here to say i delayed working on it until Drupal 4.6 came out and was settled. I will start to take a look at it again now with an aim or making it work on 4.6 of Drupal.

--
www.gadgetspy.co.uk | www.bargainspy.co.uk | www.spamfo.co.uk | www.buddasworld.co.uk

Frando’s picture

Hello,

what's the current state of affairs?

Would be wonderful if you could release a version working on 4.6 soon...

regards,
Frando

budda’s picture

Currently I'm caught up with two other modules. I'm trying to get the PayPal subscription module to work for a project, as well as development of a ProtX.com payment gateway module. These are currently more important than the affiliate.module.

Sorry.

--
www.gadgetspy.co.uk | www.bargainspy.co.uk

incidentist’s picture

I've taken this over, and am working to prep this for the newest version. There's a lot of scrubbing that has to be done. I hope to have it done within a few weeks.

--
Dan Kurtz - http://www.brickswithoutclay.com
The Rockridge Institute - http://www.rockridgeinstitute.org

jasonwhat’s picture

While you are at it, I have a few ideas and questions. In fact, maybe there is a student out there that can help and make this part of the Summer of Code.

One idea was to have the affiliates module interface with the Go module so affiliate links could be created to offsite locations. For example, a community might want to link to the Drupal donation page and track by user and by site how many people they are sending. I don't think the code as of now offers a way to integrate external sites so this may be one.

Another idea is to create some type of wizard to help users create affiliate links to virtually any page, or an admin defined set of pages rather than having one long list of links on the user's profile page that grow cumbersome quickly. Perhaps, this could work with some of the Ajax functionality already being proposed for Summer of Code.

I don't know who is really in charge of what can and can't be done in realtion to the Summer of Code, but I'm sure we could find a student developer to help in the next few days if this has a greenlight.

incidentist’s picture

Ooooh. That would be neat. A few things:

1. I need this module working Real Soon Now, so I'm gonna keep banging away at it so that I can get it working for http://www.draftwarren.com [/plug].

2. It already does the link-to-offsite-locations thing. In the Spread Firefox site, all the links point to spreadfirefox.com, but redirect to the FireFox download page. That's built into the data strcuture. However, I didn't know about the Go module, and maybe it'd be a better idea to just use that functionality instead of writing it from scratch.

In fact, it looks like Go is only good for 4.5. Does anyone know if it works out of the box for 4.6? If not, [sigh], that's one more thing to add to the ol' to-do list.

As for expanding the capabilities of the module, this is what I was thinking, and it's an idea on the sort of scale that Summer of Code projects operate on: right now, the only thing you can get points for is referring people to pages. Well, what if you could get points for other actions as well? I'm thinking you get 10 points for referring someone to a page, but 50 points if they register as a new user, or 50 points if they leave a comment, or 100 points if they pledge some money in a pledge module. It'd basically be a hook (because modules can define their own hooks), that modules could implement as they please to award points for all sorts of crazy crap. The other affiliate module already knows how to "give points" when a user registers from an affiliate link.

--
Dan Kurtz - http://www.brickswithoutclay.com
The Rockridge Institute - http://www.rockridgeinstitute.org

jasonwhat’s picture

Sadly, we didn't find a coder yet and are pretty much out of time, but at least you are on this and I'm sure some other may help if it grows in size. A gaping hole in drupal isn't just lack of an affiliate suite, but the broader lack of some type of karma, mojo, whatever to compile all these points from node moderation to what you are proposing. On large sites such ratings can be quite helpful in helping people filter through loads of content. A standarized way for any module to hook in points is important and actually sounds like a standalone that the affiliates would hook into. Watch that, "to do" list grow!

Another question, is there any type of java or some type of tracking code that could be used on third party non-Drupal sites as part of tracking. For example, let's say that Drupal decided to donate to a a major tsunami relief effort. Could they offer a snippet of code for the organization to place on their sites (non-Drupal site sadly) "thank you" or confirmation page that notifies the referrer, Drupal in this case that a donation was completed orginating at the affiliate link? Drupal can then say, "We gave x amount to relief" or "User X rounded up the most donations and is awarded the free ipod," or whatever. I know that google adwords uses similar technology with a small bit of JS. It seems like there must be some SOAP-XML way to do this as well.

incidentist’s picture

SOAP-XML. I haven't yet gotten around to digesting that particular bowl of alphabet soup. It sounds like that would be an easy thing to add on, assuming I do a decent job with this codebase.

Man, this frickin' to-do list is like 3 weeks old and it's already the size of a well-fed redwood tree. Maybe after I've cut it down Google will toss some of its excess cash my way.

--
Dan Kurtz - http://www.brickswithoutclay.com
The Rockridge Institute - http://www.rockridgeinstitute.org

kbahey’s picture

What is the status on this?

Is this the module in the repository now? I saw CVS comments about this being changed for 4.6, but not conclusive.

Does this module supercede SpreadFireFox affiliates module, or compete with it?

--
Consulting: 2bits.com
Personal: Baheyeldin.com

--
Drupal performance tuning and optimization, hosting, development, and consulting: 2bits.com, Inc. and Twitter at: @2bits
Personal blog: Ba

jasonwhat’s picture

The creator of the one on Spreadfirefox asked me to release it to the Drupal community to update and manage. Nobody has taken it on since it was released, 4.4 compatible. So this is the next version of it. It has nothing to compete against since it hasn't been updated. Hopefully, the incdentist(sp?) will be able to make a nice affiliate sweet and maybe even combine the module in contrib that is a different affiliates module. Yes, it is all very confusing. He is the one you should contact, maybe contact form.

kbahey’s picture

Yes indeed it is very confusing. I sent him a note. Will see.

--
Consulting: 2bits.com
Personal: Baheyeldin.com

--
Drupal performance tuning and optimization, hosting, development, and consulting: 2bits.com, Inc. and Twitter at: @2bits
Personal blog: Ba

incidentist’s picture

This is taking longer than I thought. But development is still active. I had to redo a lot of the code, but most of that is done now. Will make more progress this weekend.

To clarify: This module gives every user a URL they can use to get points by putting up banners on their site that point to that URL.

It differs from the Userpoints module in that it only gives points for clickthrus, and not for things like posting or registering a user.

It differs from the other affiliate module in that every user can be an affiliate, whereas with the other affiliate module, affiliate links are handed out by the administrator. The Affiliate module only logs user registrations. The SFF module is good for sites like SFF where every user will want points. The other Affiliate module is good for sites who are working with a few specific people for marketing and outreach, and would like to keep track of who is doing well.

It's easy to see how all three of these should be combined -- users should be able to accumulate points based on clickthrus, registrations, posts, pledges or anything else, and the module should be set up such that administrators can choose to give everyone affiliate permission or only certain people.

--
Dan Kurtz - http://www.brickswithoutclay.com
The Rockridge Institute - http://www.rockridgeinstitute.org

drupal999’s picture

Any progress since the 23rd of June ?

ericatkins’s picture

Any progress?

Should we start a bounty to encourage someone to finish the port?

Hushed Casket

visionleads’s picture

Here's this month's bump ;)

Why can you “Expect Success!”?
Because Your SUCCESS is my PASSION!,

Shahrooz Bhopti
Professional Problem Solver & CEO, Next Wave Network LLC
Empowering Trustworthy Relationships. Sharing collaborative innovation w/ driven compassion.

kbahey’s picture

A 4.7 version of this module is available at 2bits software downloads section.
--
Drupal development and customization: 2bits.com
Personal: Baheyeldin.com

--
Drupal performance tuning and optimization, hosting, development, and consulting: 2bits.com, Inc. and Twitter at: @2bits
Personal blog: Ba

jasonwhat’s picture

Wow, I've been looking everywhere for this, and emailing everyone I could think of at SFX.com. What version of the code did you work with to update this? Could you commit this to CVS so it isn't lost forever again :)

kbahey’s picture

The project is now on Drupal.org

Check it here http://drupal.org/project/affiliates
--
Drupal development and customization: 2bits.com
Personal: Baheyeldin.com

--
Drupal performance tuning and optimization, hosting, development, and consulting: 2bits.com, Inc. and Twitter at: @2bits
Personal blog: Ba