annotate ad.module @ 3:416ea999ed76 ad

maj ad version rc1
author sly
date Mon, 20 Apr 2009 09:49:37 +0000
parents e5584a19768b
children 6aeff3329e01
rev   line source
pierre@0 1 <?php
sly@3 2 // $Id: ad.module,v 1.2.2.29.2.83.2.16.2.21 2009/04/16 14:24:53 jeremy Exp $
pierre@0 3
pierre@0 4 /**
pierre@0 5 * @file
pierre@0 6 * An advertising system for Drupal powered websites.
pierre@0 7 *
pierre@0 8 * Copyright (c) 2005-2009.
pierre@0 9 * Jeremy Andrews <jeremy@tag1consulting.com>.
pierre@0 10 */
pierre@0 11
pierre@1 12 require_once('ad_token.inc');
pierre@0 13
pierre@0 14 /**
pierre@0 15 * Implementation of hook_theme().
pierre@0 16 */
pierre@0 17 function ad_theme() {
pierre@0 18 return array(
pierre@0 19 'ad_display' => array(
pierre@0 20 'file' => 'ad.module',
pierre@0 21 'arguments' => array(
pierre@0 22 'group' => NULL,
pierre@0 23 'display' => NULL,
pierre@0 24 'method' => 'javascript',
pierre@0 25 ),
pierre@0 26 ),
pierre@0 27 'ad_status_display' => array(
pierre@0 28 'file' => 'ad.module',
pierre@0 29 'arguments' => array(
pierre@0 30 'node' => NULL,
pierre@0 31 ),
pierre@0 32 ),
pierre@0 33 'ad_statistics_display' => array(
pierre@0 34 'file' => 'ad.pages.inc',
pierre@0 35 'arguments' => array(
pierre@0 36 'statistics' => NULL,
pierre@0 37 ),
pierre@0 38 ),
pierre@0 39 'node_ad' => array(
pierre@0 40 'file' => 'ad.pages.inc',
pierre@0 41 'arguments' => array(
pierre@0 42 'node' => NULL,
pierre@0 43 'yield_form' => TRUE,
pierre@0 44 ),
pierre@0 45 ),
pierre@0 46 'ad_admin_ads' => array(
pierre@0 47 'file' => 'ad.admin.inc',
pierre@0 48 'arguments' => array(
pierre@0 49 'form' => NULL,
pierre@0 50 ),
pierre@0 51 ),
pierre@0 52 'ad_filters' => array(
pierre@0 53 'file' => 'ad.admin.inc',
pierre@0 54 'arguments' => array(
pierre@0 55 'form' => NULL,
pierre@0 56 ),
pierre@0 57 ),
pierre@0 58 'ad_filter_form' => array(
pierre@0 59 'file' => 'ad.admin.inc',
pierre@0 60 'arguments' => array(
pierre@0 61 'form' => NULL,
pierre@0 62 ),
pierre@0 63 ),
pierre@0 64 );
pierre@0 65 };
pierre@0 66
pierre@0 67 /**
pierre@0 68 * Use this function to display ads from a specified group.
pierre@0 69 *
pierre@0 70 * @param $group
pierre@0 71 * The ad group tid to display ads from.
pierre@0 72 * @param $quantity
pierre@0 73 * Optionally specify the number of unique ads to display.
pierre@0 74 * @param $options
pierre@0 75 * Any number of options from this list: hostid, nids.
pierre@0 76 */
pierre@0 77 function ad($group = FALSE, $quantity = 1, $options = array()) {
pierre@0 78 global $base_url;
pierre@0 79
pierre@0 80 $adserve = variable_get('adserve', '');
pierre@0 81 $adserveinc = variable_get('adserveinc', '');
pierre@0 82 if (empty($adserve) || empty($adserveinc)) {
pierre@0 83 // This is probably the first time ad() has been called.
pierre@0 84 _ad_check_installation();
pierre@0 85 $adserve = variable_get('adserve', '');
pierre@0 86 $adserveinc = variable_get('adserveinc', '');
pierre@0 87 }
pierre@0 88 if (!file_exists($adserve) || !file_exists($adserveinc)) {
pierre@0 89 drupal_set_message(t('Ads cannot be displayed. The ad module is <a href="@misconfigured">misconfigured</a>, failed to locate the required <em>serve.php</em> ond/or <em>adserve.inc</em> file.', array('@misconfigured' => url('admin/content/ad/configure'))), 'error');
pierre@0 90 _ad_check_installation();
pierre@0 91 return (t('The ad module is <a href="@misconfigured">misconfigured</a>.', array('@misconfigured' => url('admin/content/ad/configure'))));
pierre@0 92 }
pierre@0 93
pierre@0 94 // Be sure a display method has been chosen.
pierre@0 95 if (!isset($options['ad_display'])) {
pierre@0 96 $options['ad_display'] = variable_get('ad_display', 'javascript');
pierre@0 97 }
pierre@0 98 $options['quantity'] = isset($quantity) ? $quantity : 1;
pierre@0 99 if (!isset($options['tids'])) {
pierre@0 100 $options['tids'] = $group;
pierre@0 101 }
pierre@0 102 $options['cache'] = variable_get('ad_cache', 'none');
pierre@0 103
pierre@0 104 switch ($options['ad_display']) {
pierre@0 105 case 'raw':
pierre@0 106 require_once(drupal_get_path('module', 'ad') .'/adserve.inc');
pierre@1 107 require_once(drupal_get_path('module', 'ad') .'/adcache.inc');
pierre@0 108 $output = adserve_ad($options);
pierre@0 109 break;
pierre@0 110 case 'iframe':
pierre@0 111 case 'jquery':
pierre@0 112 $query['m'] = $options['ad_display'];
pierre@0 113 // Fall through...
pierre@0 114 case 'javascript':
pierre@0 115 default:
pierre@0 116 $query['q'] = $quantity;
pierre@0 117 if (isset($options['hostid'])) {
pierre@0 118 $query['k'] = $options['hostid'];
pierre@0 119 }
pierre@0 120 // Allow external cache files to define additional display variables.
pierre@0 121 if ($options['cache'] != 'none') {
pierre@0 122 $query['c'] = $options['cache'];
pierre@0 123 $cache_variables = module_invoke('ad_cache_'. $options['cache'], 'adcacheapi', 'display_variables', array());
pierre@0 124 if (is_array($cache_variables)) {
pierre@0 125 foreach ($cache_variables as $key => $value) {
pierre@0 126 $query[$key] = $value;
pierre@0 127 }
pierre@0 128 }
pierre@0 129 }
pierre@0 130 // Allow ad_type modules to define additional display variables.
pierre@0 131 $type_variables = module_invoke_all('adapi', 'display_variables', array());
pierre@0 132 if (is_array($type_variables)) {
pierre@0 133 foreach ($type_variables as $key => $value) {
pierre@0 134 $query[$key] = $value;
pierre@0 135 }
pierre@0 136 }
pierre@0 137 if (isset($options['nids'])) {
pierre@0 138 // Choose ads from the provided list of node Id's.
pierre@0 139 $nids = $options['nids'];
pierre@0 140 $query['n'] = $nids;
pierre@0 141 $group = "nids-$nids";
pierre@0 142 }
pierre@0 143 else if (isset($options['tids'])) {
pierre@0 144 // Choose ads from the provided list of taxonomy terms.
pierre@0 145 $tids = $options['tids'];
pierre@0 146 $query['t'] = $tids;
pierre@0 147 $group = "tids-$tids";
pierre@0 148 }
pierre@0 149 else {
pierre@0 150 // Choose ads from the specified group.
pierre@0 151 $query['t'] = $group;
pierre@0 152 $options['tids'] = $group;
pierre@0 153 }
pierre@1 154 if (isset($options['url'])) {
pierre@1 155 $query['u'] = $options['url'];
pierre@1 156 }
pierre@1 157 else {
pierre@1 158 $query['u'] = $_GET['q'];
pierre@1 159 }
sly@2 160 $src = htmlentities(url($base_url .'/'. $adserve, array('query' => $query)));
pierre@0 161 if ($options['ad_display'] == 'iframe') {
pierre@0 162 // TODO: We need to know the IFrame size before it is displayed. This
pierre@0 163 // limits the flexibility of what can be displayed in these frames.
pierre@0 164 // For now we'll have a global value, later we'll add per-group
pierre@0 165 // over-rides.
pierre@0 166 $append = 'frameborder="'. variable_get('ad_iframe_frameborder', 0) .'" ';
pierre@0 167 $append .= 'scrolling="'. variable_get('ad_iframe_scroll', 'auto') .'" ';
pierre@0 168 $append .= 'name="'. $group .'" ';
pierre@0 169 if ($height = variable_get('ad_iframe_height', '')) {
pierre@0 170 $append .= 'height="'. $height .'" ';
pierre@0 171 }
pierre@0 172 if ($width = variable_get('ad_iframe_width', '')) {
pierre@0 173 $append .= 'width="'. $width .'" ';
pierre@0 174 }
pierre@0 175 $output = '<iframe src="'. $src ."\" $append></iframe>";
pierre@0 176 }
pierre@0 177 else if ($options['ad_display'] == 'jquery') {
pierre@0 178 // The theme function uses this to generate a CSS id for jQuery to use.
pierre@0 179 $output = $src;
pierre@0 180 }
pierre@0 181 else {
pierre@1 182 $output = "<script type='text/javascript' src='$src'></script>";
pierre@0 183 }
pierre@0 184 break;
pierre@0 185 }
pierre@0 186
pierre@0 187 if (user_access('show advertisements')) {
pierre@1 188 if (isset($options['div']) && $options['div'] !== FALSE) {
pierre@1 189 return theme('ad_display', $group, $output, $options['ad_display']);
pierre@1 190 }
pierre@1 191 else {
pierre@1 192 return theme('ad_display', $group, $output, 'raw');
pierre@1 193 }
pierre@0 194 }
pierre@0 195 else {
pierre@0 196 return theme('ad_display', 'none', "<!-- Enable 'show advertisements' permission if you wish to display ads here. -->");
pierre@0 197 }
pierre@0 198 }
pierre@0 199
pierre@0 200 /**
pierre@0 201 * Function to display the actual advertisement to the screen. Wrap it in a
pierre@0 202 * theme function to make it possible to customize in your own theme.
pierre@0 203 */
pierre@0 204 function theme_ad_display($group, $display, $method = 'javascript') {
pierre@1 205 static $id = -1;
pierre@1 206
pierre@1 207 // Increment counter for displaying multiple advertisements on the page.
pierre@1 208 $id++;
pierre@0 209
pierre@0 210 // The naming convention for the id attribute doesn't allow commas.
pierre@0 211 $group = preg_replace('/[,]/', '+', $group);
pierre@0 212
pierre@0 213 if ($method == 'jquery') {
pierre@0 214 drupal_add_js('misc/jquery.js', 'core');
pierre@1 215 return "\n<div class=\"advertisement group-$group\" id=\"group-id-$id\">\n <script type=\"text/javascript\">\n//<![CDATA[\n $(document).ready(function(){ jQuery(\"div#group-id-$id\").load(\"$display\"); });\n //]]>\n </script>\n</div>\n";
pierre@1 216 }
pierre@1 217 else if ($method == 'raw') {
pierre@1 218 return $display;
pierre@0 219 }
pierre@0 220 else {
pierre@0 221 return "\n<div class=\"advertisement group-$group\" id=\"group-id-$group\">$display</div>\n";
pierre@0 222 }
pierre@0 223 }
pierre@0 224
pierre@0 225 /**
pierre@0 226 * Update click counter then redirect host to ad's target URL.
pierre@0 227 */
pierre@1 228 function ad_redirect($aid, $group = NULL) {
pierre@0 229 global $user;
pierre@1 230 $hostid = isset($_GET['hostid']) ? $_GET['hostid'] : '';
pierre@1 231 $extra = isset($_GET['extra']) ? $_GET['extra'] : '';
pierre@0 232 if (function_exists('click_filter_status')) {
pierre@0 233 $status = click_filter_status($aid, $hostid);
pierre@0 234 if ($status == CLICK_VALID) {
pierre@0 235 ad_statistics_increment($aid, 'click', $group, $hostid);
pierre@0 236 }
pierre@0 237 }
pierre@0 238 else {
pierre@0 239 // We're not filtering clicks, so all clicks are valid.
pierre@0 240 ad_statistics_increment($aid, 'click', $group, $hostid);
pierre@0 241 $status = 0;
pierre@0 242 }
pierre@0 243 // Allow source url to be passed in.
pierre@0 244 $url = isset($_GET['u']) ? $_GET['u'] : '';
pierre@0 245 if (!isset($url) || !valid_url($url)) {
pierre@0 246 $url = referer_uri();
pierre@0 247 }
pierre@1 248 db_query("INSERT INTO {ad_clicks} (aid, uid, status, hostname, user_agent, adgroup, extra, hostid, url, timestamp) VALUES (%d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d)", $aid, $user->uid, $status, ip_address(), $_SERVER['HTTP_USER_AGENT'], $group, $extra, $hostid, $url, time());
pierre@0 249
pierre@0 250 // Determine where we're supposed to redirect the user.
pierre@0 251 $adtype = db_result(db_query('SELECT adtype FROM {ads} WHERE aid = %d', $aid));
pierre@0 252
pierre@0 253 $node->nid = $node->aid = $aid;
pierre@0 254 $node->hostid = $hostid;
pierre@0 255 $url = module_invoke('ad_'. $adtype, 'adapi', 'redirect', $node);
pierre@0 256 if (isset($url)) {
pierre@0 257 watchdog('ad', 'Clicked %type ad aid %aid hostid %hostid.', array('%type' => $adtype, '%aid' => $aid, '%hostid' => $hostid));
pierre@0 258 header('Location: '. $url);
pierre@0 259 }
pierre@0 260 else {
pierre@0 261 watchdog('ad', 'Ad redirection failed for aid %aid hostid %hostid, failed to load destination URL. ', array('%aid' => $aid, '%hostid' => $hostid));
pierre@0 262 drupal_goto('');
pierre@0 263 }
pierre@0 264 }
pierre@0 265
pierre@0 266 /**
pierre@0 267 * Ad API Helper Function:
pierre@0 268 * Append all necessary attributes to <a> tags.
pierre@0 269 */
pierre@0 270 function ad_link_attributes() {
pierre@0 271 return array_merge(ad_link_target(TRUE), ad_link_nofollow(TRUE));
pierre@0 272 }
pierre@0 273
pierre@0 274 /**
pierre@0 275 * Ad API Helper Function:
pierre@0 276 * Provide XHTML-strict-compatible target window onclick-handlers based on
pierre@0 277 * global configuration.
pierre@0 278 */
pierre@0 279 function ad_link_target() {
pierre@0 280 switch (variable_get('ad_link_target', '_self')) {
pierre@0 281 case '_blank':
pierre@0 282 $target = array('onclick' => 'window.open(this.href); return false;');
pierre@0 283 break;
pierre@0 284 case '_parent':
pierre@0 285 $target = array('onclick' => 'window.parent.location = this.href; return false;');
pierre@0 286 break;
pierre@0 287 case '_top':
pierre@0 288 $target = array('onclick' => 'window.top.location = this.href; return false;');
pierre@0 289 break;
pierre@0 290 default:
pierre@0 291 $target = array();
pierre@0 292 break;
pierre@0 293 }
pierre@0 294 return $target;
pierre@0 295 }
pierre@0 296
pierre@0 297 /**
pierre@1 298 * Force the cache to be flushed.
pierre@1 299 */
pierre@1 300 function ad_rebuild_cache($verbose = FALSE) {
pierre@1 301 $cache = variable_get('ad_cache', 'none');
pierre@1 302 $build = "ad_cache_{$cache}_build";
pierre@1 303 if (function_exists($build)) {
pierre@1 304 if ($verbose) {
pierre@1 305 drupal_set_message('Rebuilding ad cache.');
pierre@1 306 }
pierre@1 307 $build();
pierre@1 308 }
pierre@1 309 }
pierre@1 310
pierre@1 311 /**
pierre@0 312 * Ad API Helper Function:
pierre@0 313 * Append rel="nofollow" if globally enabled.
pierre@0 314 */
pierre@0 315 function ad_link_nofollow() {
pierre@0 316 if (variable_get('ad_link_nofollow', 0)) {
pierre@0 317 $nofollow = array('rel' => 'nofollow');
pierre@0 318 }
pierre@0 319 else {
pierre@0 320 $nofollow = array();
pierre@0 321 }
pierre@0 322 return $nofollow;
pierre@0 323 }
pierre@0 324
pierre@0 325 /**
pierre@0 326 * Increment action counter.
pierre@0 327 */
pierre@0 328 function ad_statistics_increment($aid, $action, $group = NULL, $hostid = NULL) {
pierre@0 329 // Update action statistics.
pierre@0 330 db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE date = %d AND aid = %d AND action = '%s' AND adgroup = '%s' AND hostid = '%s'", date('YmdH'), $aid, $action, $group, $hostid);
pierre@0 331 // If column doesn't already exist, we need to add it.
pierre@0 332 if (!db_affected_rows()) {
pierre@0 333 db_query("INSERT INTO {ad_statistics} (aid, adgroup, hostid, date, action, count) VALUES(%d, '%s', '%s', %d, '%s', 1)", $aid, $group, $hostid, date('YmdH'), $action);
pierre@0 334 // If another process already added this row our INSERT will fail, if so we
pierre@0 335 // still need to increment it so we don't loose an action.
pierre@0 336 if (!db_affected_rows()) {
pierre@0 337 db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE date = %d AND aid = %d AND action = '%s' AND adgroup = '%s' AND hostid = '%s'", date('YmdH'), $aid, $action, $group, $hostid);
pierre@0 338 }
pierre@0 339 }
pierre@0 340
pierre@0 341 $event = array('aid' => $aid, 'action' => $action, 'hostid' => $hostid);
pierre@0 342 module_invoke_all('adapi', 'statistics_increment', $event);
pierre@0 343 }
pierre@0 344
pierre@1 345 /**
pierre@1 346 * Return an array with all status values user has permission to set.
pierre@1 347 * A user with 'administer advertisements' permission can update any status.
pierre@1 348 */
pierre@1 349 function ad_status_array($aid = 0, $status = NULL) {
pierre@1 350 $permissions = array();
pierre@1 351 // mark status as pending
pierre@1 352 if (user_access('administer advertisements') ||
pierre@1 353 $status == 'pending' || $status == NULL ||
pierre@1 354 ad_permission($aid, 'set status as pending')) {
pierre@1 355 $permissions['pending'] = t('This advertisement is currently waiting for administrative approval.');
pierre@0 356 }
pierre@1 357 // mark status from pending to approved
pierre@1 358 if (user_access('administer advertisements') ||
pierre@1 359 $status == 'approved' ||
pierre@1 360 ($status == 'pending' &&
pierre@1 361 ad_permission($aid, 'set status from pending to approved'))) {
pierre@1 362 $permissions['approved'] = t('This advertisement has been approved and is currently waiting to be activated.');
pierre@0 363 }
pierre@1 364 // mark status as active (from pending, approved, or offline)
pierre@1 365 if (user_access('administer advertisements') ||
pierre@1 366 $status == 'active' ||
pierre@1 367 ($status == 'approved' &&
pierre@1 368 ad_permission($aid, 'set status from approved to active')) ||
pierre@1 369 ($status == 'offline' &&
pierre@1 370 ad_permission($aid, 'set status from offline to active'))) {
pierre@1 371 $permissions['active'] = t('This advertisement is actively being displayed.');
pierre@1 372 }
pierre@1 373 // mark status as offline (from pending, approved, or active)
pierre@1 374 if (user_access('administer advertisements') ||
pierre@1 375 $status == 'offline' ||
pierre@1 376 ($status == 'approved' &&
pierre@1 377 ad_permission($aid, 'set status from approved to offline')) ||
pierre@1 378 ($status == 'active' &&
pierre@1 379 ad_permission($aid, 'set status from active to offline'))) {
pierre@1 380 $permissions['offline'] = t('This advertisement has been temporarily disabled by its owner and is not currently being displayed.');
pierre@1 381 }
pierre@1 382 // mark status as expired (from active or offline)
pierre@1 383 if (user_access('administer advertisements') ||
pierre@1 384 $status == 'expired' ||
pierre@1 385 ($status == 'active' &&
pierre@1 386 ad_permission($aid, 'set status from active to expired')) ||
pierre@1 387 ($status == 'offline' &&
pierre@1 388 ad_permission($aid, 'set status from offline to expired'))) {
pierre@1 389 $permissions['expired'] = t('This advertisement has expired and is no longer being displayed.');
pierre@1 390 }
pierre@1 391 // mark status as denied (from pending or any)
pierre@1 392 if (user_access('administer advertisements') ||
pierre@1 393 $status == 'denied' ||
pierre@1 394 ($status == 'pending' &&
pierre@1 395 ad_permission($aid, 'set status from pending to denied')) ||
pierre@1 396 ad_permission($aid, 'set status as denied')) {
pierre@1 397 $permissions['denied'] = t('This advertisement was refused by the site administrator and will not be displayed.');
pierre@1 398 }
pierre@1 399 return $permissions;
pierre@0 400 }
pierre@0 401
pierre@0 402 /**
pierre@0 403 * Display the status of the currently viewed ad.
pierre@0 404 */
pierre@0 405 function theme_ad_status_display($node) {
pierre@1 406 if (isset($node->adstatus)) {
pierre@1 407 $status_array = ad_status_array($node->nid, $node->adstatus);
pierre@1 408 $output = '<div class="adstatus">';
pierre@1 409 $output .= '<p>'. t($status_array[$node->adstatus]) .'</p>';
pierre@1 410 switch ($node->adstatus) {
pierre@1 411 case 'approved':
pierre@1 412 if ($node->autoactivate) {
pierre@1 413 $output .= '<p>'. t('This advertisement will be automatically activated on %timestamp, in %time.', array('%timestamp' => format_date($node->autoactivate, 'large'), '%time' => format_interval($node->autoactivate - time()))) .'</p>';
pierre@1 414 }
pierre@1 415 break;
pierre@1 416 case 'active':
pierre@1 417 $activated = db_result(db_query("SELECT activated FROM {ads} WHERE aid = %d", $node->nid));
pierre@1 418 if ($activated) {
pierre@1 419 $output .= '<p>'. t('This advertisement has been active since %date.', array('%date' => format_date($activated, 'large'))) .'</p>';
pierre@1 420 }
pierre@1 421 if ($node->autoexpire) {
pierre@1 422 $output .= '<p>'. t('This advertisement will expire on %timestamp, in %time.', array('%timestamp' => format_date($node->autoexpire, 'large'), '%time' => format_interval($node->autoexpire - time()))) .'</p>';
pierre@1 423 }
pierre@1 424 if ($node->maxviews) {
pierre@1 425 $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $node->nid, date('YmdH', $node->activated)));
pierre@1 426 $output .= '<p>'. t('This advertisement will expire after %left more impressions.', array('%left' => $node->maxviews - $views)) .'</p>';
pierre@1 427 }
pierre@1 428 if ($node->maxclicks) {
pierre@1 429 $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $node->nid, date('YmdH', $node->activated)));
pierre@1 430 $output .= '<p>'. t('This advertisement will expire after %left more clicks.', array('%left' => $node->maxclicks - $clicks)) .'</p>';
pierre@1 431 }
pierre@1 432 break;
pierre@1 433 case 'expired':
pierre@1 434 $expired = db_result(db_query("SELECT expired FROM {ads} WHERE aid = %d", $node->nid));
pierre@1 435 if ($expired) {
pierre@1 436 $output .= '<p>'. t('This advertisement expired %date.', array('%date' => format_date($expired, 'large'))) .'</p>';
pierre@1 437 }
pierre@1 438 break;
pierre@1 439 }
pierre@1 440 $output .= '</div>';
pierre@1 441 return theme('box', t('Status'), $output);
pierre@0 442 }
pierre@0 443 }
pierre@0 444
pierre@0 445 /**
pierre@0 446 * Implementation of hook_help().
pierre@0 447 */
pierre@0 448 function ad_help($path, $arg) {
pierre@0 449 $output = '';
pierre@0 450 switch ($path) {
pierre@0 451 case 'admin/help#ad':
pierre@0 452 $output = '<p>'. t('The ad module provides a complete advertising system for Drupal powered websites. It does this through an API that allow other modules to handle various types of advertising content. For example, if enabled together with the ad_image module you will be able to display image based advertisements such as banner ads.') .'</p>';
pierre@0 453 break;
pierre@0 454 case 'node/add/ad':
pierre@0 455 $output = '<p>'. t('Advertisements can be randomly displayed to visitors of your website.') .'</p>';
pierre@0 456 break;
pierre@0 457 }
pierre@0 458 return $output;
pierre@0 459 }
pierre@0 460
pierre@0 461 /**
pierre@0 462 * Implementation of hook_cron().
pierre@0 463 */
pierre@0 464 function ad_cron() {
pierre@0 465 if (time() - variable_get('ad_cron_timestamp', 0) >= 60) {
pierre@0 466 // Locate ads that need to be activated or expired.
pierre@0 467 $result = db_query('SELECT aid, adstatus, adtype, autoactivate, autoactivated, autoexpire, autoexpired FROM {ads} WHERE autoactivate <> 0 OR autoexpire <> 0');
pierre@0 468 while ($ad = db_fetch_object($result)) {
pierre@0 469 switch ($ad->adstatus) {
pierre@0 470 case 'approved': {
pierre@0 471 // See if this ad is ready to be activated.
pierre@0 472 if ($ad->autoactivate && $ad->autoactivate <= time()) {
pierre@0 473 $node = node_load($ad->aid);
pierre@0 474
pierre@0 475 // Activate the ad.
pierre@0 476 db_query("UPDATE {ads} SET adstatus = 'active', autoactivate = 0, autoactivated = %d, activated = %d WHERE aid = %d", time(), time(), $ad->aid);
pierre@0 477 ad_statistics_increment($ad->aid, 'autoactivated');
pierre@0 478 ad_statistics_increment($ad->aid, 'active');
pierre@0 479
pierre@0 480 watchdog('ad', 'Automatically activated ad %title with nid %nid.', array('%title' => $node->title, '%nid' => $node->nid));
pierre@0 481
pierre@0 482 // Allow modules to do special processing to automatically
pierre@0 483 // activated advertisements.
pierre@0 484 module_invoke('ad_'. $ad->adtype, 'adapi', 'autoactivate', $node);
pierre@0 485 }
pierre@0 486 else if (!$ad->autoactivate) {
pierre@0 487 // Once daily warn that there's an ad stuck in approved state.
pierre@0 488 if (time() - variable_get("ad_autoactivate_warning_$ad->aid", 0) >= 8600) {
pierre@0 489 watchdog('ad', 'Warning: ad %title with nid %nid in approved state has no autoactivate date set.', array('%title' => $node->title, '%nid' => $node->nid));
pierre@0 490 variable_set("ad_autoactivate_warning_$ad->aid", time());
pierre@0 491 }
pierre@0 492 }
pierre@0 493 break;
pierre@0 494 }
pierre@0 495 case 'active': {
pierre@0 496 // See if this ad is ready to be activated.
pierre@0 497 if ($ad->autoexpire && $ad->autoexpire <= time()) {
pierre@0 498 $node = node_load($ad->aid);
pierre@0 499
pierre@0 500 // Expire the ad.
pierre@0 501 db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $ad->aid);
pierre@0 502 ad_statistics_increment($ad->aid, 'autoexpired');
pierre@0 503 ad_statistics_increment($ad->aid, 'expired');
pierre@0 504
pierre@0 505 watchdog('ad', 'Automatically expired ad %title with nid %nid.', array('%title' => $node->title, '%nid' => $node->nid));
pierre@0 506
pierre@0 507 // Allow modules to do special processing to automatically
pierre@0 508 // activated advertisements.
pierre@0 509 module_invoke('ad_'. $ad->adtype, 'adapi', 'autoexpire', $node);
pierre@0 510 }
pierre@0 511 else if (!$ad->autoexpire) {
pierre@0 512 // Ad is already activated, but has autoactivate timestamp set.
pierre@0 513 db_query("UPDATE {ads} SET autoactivate = 0 WHERE aid = %d", $ad->aid);
pierre@0 514 }
pierre@0 515 break;
pierre@0 516 }
pierre@0 517 default:
pierre@0 518 $node = node_load($ad->aid);
pierre@0 519 db_query('UPDATE {ads} SET autoactivate = 0, autoexpire = 0 WHERE aid = %d', $ad->aid);
pierre@0 520 watchdog('ad', 'Warning: reset %type timestamp on advertisement %title with nid %nid because it is in %state state.', array('%title' => $node->title, '%nid' => $node->nid, '%type' => $ad->autoactivate ? 'autoactivate' : 'autoexpire', '%state' => $ad->adstatus));
pierre@0 521 }
pierre@0 522 }
pierre@0 523 variable_set('ad_cron_timestamp', time());
pierre@0 524 }
pierre@0 525 }
pierre@0 526
pierre@0 527 /**
pierre@0 528 * Implementation of hook_perm().
pierre@0 529 */
pierre@0 530 function ad_perm() {
pierre@0 531 return array('administer advertisements',
pierre@0 532 'create advertisements',
pierre@0 533 'edit own advertisements',
pierre@1 534 'edit any advertisement',
pierre@1 535 'delete own advertisements',
pierre@1 536 'delete any advertisement',
pierre@0 537 'show advertisements');
pierre@0 538 }
pierre@0 539
pierre@0 540 /**
pierre@0 541 * Implementation of hook_node_info().
pierre@0 542 */
pierre@0 543 function ad_node_info() {
pierre@0 544 $items['ad'] = array(
pierre@0 545 'name' => t('Advertisement'),
pierre@0 546 'module' => 'ad',
pierre@0 547 'description' => t('Advertisements can be randomly displayed to visitors of your website.'),
pierre@0 548 );
pierre@0 549 return $items;
pierre@0 550 }
pierre@0 551
pierre@0 552 /**
pierre@0 553 * Implementation of hook_access().
pierre@0 554 */
pierre@0 555 function ad_access($op, $node, $account) {
pierre@1 556 switch ($op) {
pierre@1 557 case 'create':
pierre@1 558 return (user_access('create advertisements', $account) || user_access('administer advertisements'));
pierre@1 559 case 'update':
pierre@1 560 return (user_access('edit any advertisement', $account) || (user_access('edit own advertisements', $account) && is_ad_owner($node->nid)) || user_access('administer advertisements', $account));
pierre@1 561 case 'delete':
pierre@1 562 return (user_access('delete any advertisement', $account) || (user_access('delete own advertisements', $account) && is_ad_owner($node->nid)) || user_access('administer advertisements', $account));
pierre@1 563 case 'view':
pierre@1 564 return (user_access('show advertisements', $account) || user_access('administer advertisements', $account));
pierre@0 565 }
pierre@0 566 }
pierre@0 567
pierre@0 568 /**
pierre@0 569 * Implementation of hook_form().
pierre@0 570 */
pierre@1 571 function ad_form(&$node, &$form_state) {
pierre@0 572 $form = array();
pierre@0 573
pierre@1 574 // When form_state is not empty, we should rather use it's values
pierre@1 575 // to not loose data if validation fails.
pierre@1 576 if (!empty($form_state['values'])) {
pierre@1 577 $node = (object)$form_state['values'];
pierre@0 578 }
pierre@0 579
pierre@0 580 $form['aid'] = array(
pierre@0 581 '#type' => 'value',
pierre@0 582 '#value' => isset($node->nid) ? $node->nid : 0,
pierre@0 583 );
pierre@0 584
pierre@0 585 $form['title'] = array(
pierre@0 586 '#type' => 'textfield',
pierre@0 587 '#title' => t('Title'),
pierre@0 588 '#required' => TRUE,
pierre@0 589 '#default_value' => isset($node->title) ? $node->title : '',
pierre@0 590 );
pierre@0 591 $form['body_filter']['body'] = array(
pierre@0 592 '#type' => 'textarea',
pierre@0 593 '#title' => t('Description'),
pierre@0 594 '#default_value' => isset($node->body) ? $node->body : '',
pierre@0 595 '#rows' => 3
pierre@0 596 );
pierre@0 597 $form['body_filter']['format'] = filter_form($node->format);
pierre@0 598
pierre@0 599 // determine the current ad type
pierre@0 600 if (!isset($adtype)) {
pierre@0 601 $adtypes = ad_get_types();
pierre@0 602 if (sizeof($adtypes) == 1) {
pierre@0 603 $adtype = key($adtypes);
pierre@0 604 }
pierre@0 605 else if (!sizeof($adtypes)) {
pierre@0 606 drupal_set_message(t('At least one ad type module must be enabled before you can create advertisements. For example, try <a href="!url">enabling</a> the ad_text or ad_image module.', array('!url' => url('admin/build/modules'))), 'error');
pierre@0 607 }
pierre@0 608 }
pierre@0 609
pierre@1 610 // display ad type switch
pierre@1 611 if (!isset($node->adtype) || isset($node->adtype_select)) {
pierre@1 612 $adtypes = array(0 => '---');
pierre@1 613 $adtypes += ad_get_types('name');
pierre@1 614 $form['select'] = array(
pierre@1 615 '#type' => 'fieldset',
pierre@1 616 '#title' => t('Select Ad type'),
pierre@1 617 '#prefix' => '<div class="container-inline">',
pierre@1 618 '#suffix' => '</div>',
pierre@1 619 '#weight' => 3,
pierre@1 620 );
pierre@1 621 $form['select']['adtype_select'] = array(
pierre@1 622 '#type' => 'select',
pierre@1 623 '#required' => TRUE,
pierre@1 624 '#options' => $adtypes,
pierre@1 625 '#default_value' => isset($node->adtype_select) ? $node->adtype_select : '',
pierre@1 626 );
pierre@1 627 $form['select']['adtype_submit'] = array(
pierre@1 628 '#type' => 'submit',
pierre@1 629 '#value' => t('Select'),
pierre@1 630 '#validate' => array('ad_select_adtype'),
pierre@1 631 '#ahah' => array(
pierre@1 632 'path' => 'node/add/ad/ahah',
pierre@1 633 'wrapper' => 'adtype-ahah-wrapper',
pierre@1 634 ),
pierre@1 635 );
pierre@1 636 }
pierre@0 637 // display type-specific options
pierre@1 638 if (isset($node->adtype) && $node->adtype) {
pierre@1 639 if (isset($node->adtype_select) && $node->adtype_select && ($node->adtype_select != $node->adtype)) {
pierre@1 640 $node->adtype = $node->adtype_select;
pierre@0 641 }
pierre@1 642 ad_form_add_adtype_elements($form, $node->adtype, $node);
pierre@1 643 // add ahah wrapper
pierre@1 644 $form['adtype_elements']['#prefix'] = '<div id="adtype-ahah-wrapper">';
pierre@1 645 $form['adtype_elements']['#suffix'] = '</div>';
pierre@1 646 }
pierre@1 647 if (!isset($form['adtype_elements'])) {
pierre@1 648 $form['adtype_elements'] = array(
pierre@1 649 '#value' => '<div id="adtype-ahah-wrapper"></div>',
pierre@1 650 '#weight' => 3.1,
pierre@0 651 );
pierre@0 652 }
pierre@0 653
pierre@1 654 // fieldset for updating ad status
pierre@1 655 $form['adstatus'] = array(
pierre@1 656 '#type' => 'fieldset',
pierre@1 657 '#title' => t('Status'),
pierre@1 658 '#collapsible' => TRUE,
pierre@1 659 '#weight' => 4,
pierre@1 660 );
pierre@1 661 $nid = isset($node->nid) ? $node->nid : 0;
pierre@1 662 $adstatus = isset($node->adstatus) ? $node->adstatus : '';
pierre@1 663 // display all available status options
pierre@1 664 foreach (ad_status_array($nid, $adstatus) as $status => $description) {
pierre@1 665 $form['adstatus']["ad$status"] = array(
pierre@1 666 '#type' => 'radio',
pierre@1 667 '#title' => t("$status"),
pierre@1 668 '#return_value' => $status,
pierre@1 669 '#default_value' => isset($node->adstatus) ? $node->adstatus : 'pending',
pierre@1 670 '#description' => "$description",
pierre@1 671 '#parents' => array("adstatus")
pierre@0 672 );
pierre@0 673 }
pierre@0 674
pierre@0 675 // display scheduling options
pierre@0 676 $form['schedule'] = array(
pierre@0 677 '#type' => 'fieldset',
pierre@0 678 '#title' => t('Scheduling'),
pierre@0 679 '#collapsible' => TRUE,
pierre@0 680 // Collapse if there isn't any scheduling data set.
pierre@0 681 '#collapsed' => (
pierre@0 682 isset($node->autoactivate) ||
pierre@0 683 isset($form_state['values']['autoactivate']) ||
pierre@0 684 isset($node->autoexpire) ||
pierre@0 685 isset($form_state['values']['autoexpire']) ||
pierre@0 686 isset($node->maxviews) ||
pierre@0 687 isset($form_state['values']['maxviews']) ||
pierre@0 688 isset($node->maxclicks) ||
pierre@0 689 isset($form_state['values']['maxclicks']))
pierre@0 690 ? FALSE : TRUE,
pierre@0 691 );
pierre@0 692
pierre@1 693 if ((isset($node->nid) && ad_permission($node->nid, 'manage status')) ||
pierre@1 694 user_access('administer advertisements')) {
pierre@0 695 $form['schedule']['current'] = array(
pierre@0 696 '#type' => 'markup',
pierre@0 697 '#prefix' => '<div>',
pierre@0 698 '#suffix' => '</div>',
pierre@0 699 '#value' => t('The current date and time is "%date".', array('%date' => format_date(time(), 'custom', 'F j, Y H:i')))
pierre@0 700 );
pierre@0 701 $form['schedule']['autoactivate'] = array(
pierre@0 702 '#type' => 'textfield',
pierre@0 703 '#title' => t('Automatically activate ad'),
pierre@0 704 '#required' => FALSE,
pierre@0 705 '#default_value' => isset($node->autoactivate) && $node->autoactivate > 0 ? format_date((int)$node->autoactivate, 'custom', 'F j, Y H:i') : 0,
pierre@0 706 '#description' => t('You can specify a date and time for this advertisement to be automatically activated. The advertisement needs to be in an <em>approved</em> state before it can be automatically activated. If you prefer to activate the advertisement immediately, leave this field empty.')
pierre@0 707 );
pierre@0 708 }
pierre@0 709
pierre@0 710 if (user_access('administer advertisements')) {
pierre@0 711 // admins can expire advertisements
pierre@0 712 $form['schedule']['autoexpire'] = array(
pierre@0 713 '#type' => 'textfield',
pierre@0 714 '#title' => t('Automatically expire ad'),
pierre@0 715 '#required' => FALSE,
pierre@0 716 '#default_value' => isset($node->autoexpire) && $node->autoexpire > 0 ? format_date((int)$node->autoexpire, 'custom', 'F j, Y H:i') : 0,
pierre@0 717 '#description' => t('You can specify a date and time for this advertisement to be automatically expired. If you don\'t want the advertisement to expire, leave this field empty.')
pierre@0 718 );
pierre@0 719 $form['schedule']['maxviews'] = array(
pierre@0 720 '#type' => 'textfield',
pierre@0 721 '#title' => t('Maximum impressions'),
pierre@0 722 '#required' => FALSE,
pierre@0 723 '#size' => 10,
pierre@0 724 '#maxlength' => 11,
pierre@0 725 '#default_value' => isset($node->maxviews) ? $node->maxviews : 0,
pierre@0 726 '#description' => t('You can specify the maximum number of times this advertisement should be displayed, after which it will be automatically expired. If you don\'t want this advertisement to expire after a certain number of impressions, leave this field set to %zero.', array('%zero' => '0')),
pierre@0 727 );
pierre@0 728 $form['schedule']['maxclicks'] = array(
pierre@0 729 '#type' => 'textfield',
pierre@0 730 '#title' => t('Maximum clicks'),
pierre@0 731 '#required' => FALSE,
pierre@0 732 '#size' => 10,
pierre@0 733 '#maxlength' => 11,
pierre@0 734 '#default_value' => isset($node->maxclicks) ? $node->maxclicks : 0,
pierre@0 735 '#description' => t('You can specify the maximum number of times this advertisement should be clicked, after which it will be automatically expired. If you don\'t want this advertisement to expire after a certain number of clicks leave this field set to %zero.', array('%zero' => '0')),
pierre@0 736 );
pierre@0 737 }
pierre@0 738 else {
pierre@0 739 // display expiration time
pierre@0 740 $form['schedule']['autoexpire_display'] = array(
pierre@0 741 '#type' => 'markup',
pierre@0 742 '#prefix' => '<div>',
pierre@0 743 '#suffix' => '</div>',
pierre@0 744 '#value' => theme('ad_status_display', $node),
pierre@0 745 );
pierre@0 746 $form['schedule']['autoexpire'] = array(
pierre@0 747 '#type' => 'hidden',
pierre@0 748 '#value' => isset($node->autoexpire) ? $node->autoexpire : 0,
pierre@0 749 );
pierre@0 750 }
pierre@0 751
pierre@1 752 $form['#validate'][] = 'ad_select_adtype';
pierre@0 753 return $form;
pierre@0 754 }
pierre@0 755
pierre@0 756 /**
pierre@1 757 * Ad type switch submit handler.
pierre@1 758 */
pierre@1 759 function ad_select_adtype(&$form, &$form_state) {
pierre@1 760 if (!$form_state['values']['adtype'] && !$form_state['values']['adtype_select']) {
pierre@1 761 form_set_error('adtype_select', t('Please, select an Ad type.'));
pierre@1 762 }
pierre@1 763 if (!isset($form_state['values']['adtype']) || isset($form_state['values']['adtype_select']) && $form_state['values']['adtype'] != $form_state['values']['adtype_select']) {
pierre@1 764 $form_state['values']['adtype'] = $form_state['values']['adtype_select'];
pierre@1 765 $form_state['rebuild'] = TRUE;
pierre@1 766 }
pierre@1 767 }
pierre@1 768
pierre@1 769 /**
pierre@1 770 * Ad type switch AHAH menu handler.
pierre@1 771 */
pierre@1 772 function ad_form_ahah() {
pierre@1 773 $form_state = array('storage' => NULL, 'submitted' => FALSE);
pierre@1 774 $form_build_id = $_POST['form_build_id'];
pierre@1 775 $form = form_get_cache($form_build_id, $form_state);
pierre@1 776 ad_form_add_adtype_elements($form, $_POST['adtype_select']);
pierre@1 777 form_set_cache($form_build_id, $form, $form_state);
pierre@1 778 $form += array(
pierre@1 779 '#post' => $_POST,
pierre@1 780 '#programmed' => FALSE,
pierre@1 781 );
pierre@1 782 // Rebuild the form.
pierre@1 783 $form = form_builder($_POST['form_id'], $form, $form_state);
pierre@1 784 $output = drupal_render($form['adtype_elements']);
pierre@1 785 drupal_json(array(
pierre@1 786 'status' => TRUE,
pierre@1 787 'data' => $output,
pierre@1 788 ));
pierre@1 789 }
pierre@1 790
pierre@1 791 /**
pierre@1 792 * Loads Ad type elements into form.
pierre@1 793 */
pierre@1 794 function ad_form_add_adtype_elements(&$form, $adtype, $node = NULL) {
pierre@1 795 unset($form['adtype_elements']);
pierre@1 796 $form['adtype_elements'] = module_invoke('ad_'. $adtype, 'adapi', 'form', $node);
pierre@1 797 $form['adtype'] = array(
pierre@1 798 '#type' => 'hidden',
pierre@1 799 '#value' => $adtype,
pierre@1 800 );
pierre@1 801 $form['adtype_elements']['#weight'] = 3.1;
pierre@1 802 }
pierre@1 803
pierre@1 804 /**
pierre@0 805 * Implementation of hook_form_alter().
pierre@0 806 */
pierre@0 807 function ad_form_alter(&$form, &$form_state, $form_id) {
pierre@0 808 if ($form_id == 'taxonomy_form_vocabulary') {
pierre@0 809 // Remove taxonomy form options not applicable for ad groups.
pierre@0 810 if ($form['vid']['#value'] == _ad_get_vid()) {
pierre@0 811 $form['help_ad_vocab'] = array(
pierre@0 812 '#value' => t('This vocabulary was automatically created for use by the ad module. Only applicable options are available.'),
pierre@0 813 '#weight' => -1
pierre@0 814 );
pierre@0 815 $form['nodes']['ad'] = array(
pierre@0 816 '#type' => 'checkbox',
pierre@0 817 '#title' => t('ad group'),
pierre@0 818 '#value' => 1,
pierre@0 819 '#attributes' => array('disabled' => ''),
pierre@0 820 '#description' => t('Type %type is required to use this vocabulary.', array('%type' => t('ad group')))
pierre@0 821 );
pierre@0 822 $form['tags']['#description'] = t('If enabled, ads are categorized by typing ad group names instead of choosing them from a list.');
pierre@0 823 $form['multiple']['#description'] = t('If enabled, allows ads to have more than one ad group (always true for free tagging).');
pierre@0 824 $form['required']['#description'] = t('If enabled, every ad <strong>must</strong> be assigned to at least one ad group.');
pierre@0 825 $form['hierarchy'] = array(
pierre@0 826 '#type' => 'value',
pierre@0 827 '#value' => 0
pierre@0 828 );
pierre@0 829 unset($form['relations']);
pierre@0 830 }
pierre@0 831 else {
pierre@0 832 unset($form['nodes']['ad']);
pierre@0 833 }
pierre@0 834 }
pierre@0 835 else if ($form_id == 'taxonomy_form_term') {
pierre@0 836 if ($form['vid']['#value'] == _ad_get_vid()) {
pierre@0 837 $form['name']['#title'] = t('Ad group name');
pierre@0 838 $form['name']['#description'] = t('The name for this ad group. Example: "Linux".');
pierre@0 839 $form['description']['#description'] = t('A description of the ad group.');
pierre@0 840 $form['description']['#required'] = TRUE;
pierre@0 841 $form['weight']['#description'] = t('In listings, the heavier ad groups will sink and the lighter ad groups will be positioned nearer the top.');
pierre@0 842 unset($form['synonyms']);
pierre@0 843 }
pierre@0 844 }
sly@3 845 else if ($form_id == 'search_form' && variable_get('ad_no_search', 1) && !user_access('administer advertisements') && !user_access('administer any advertisement')) {
sly@3 846 $vid = _ad_get_vid();
sly@3 847 $vocabulary = db_result(db_query('SELECT name FROM {vocabulary} WHERE vid = %d', $vid));
sly@3 848 unset($form['advanced']['category']['#options'][$vocabulary]);
sly@3 849 if (empty($form['advanced']['category']['#options'])) {
sly@3 850 unset($form['advanced']['category']);
sly@3 851 }
sly@3 852 unset($form['advanced']['type']['#options']['ad']);
sly@3 853 }
sly@3 854 }
sly@3 855
sly@3 856 /**
sly@3 857 * Implementation of hook_db_rewrite_sql().
sly@3 858 */
sly@3 859 function ad_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
sly@3 860 if (variable_get('ad_no_search', 1) && !user_access('administer advertisements') && !user_access('edit any advertisement') && $query == '' && $primary_table == 'n' && $primary_field = 'nid' && empty($args)) {
sly@3 861 return array('where' => " n.type != 'ad'");
sly@3 862 }
pierre@0 863 }
pierre@0 864
pierre@0 865 /**
pierre@0 866 * Implementation of hook_nodeapi().
pierre@0 867 */
pierre@0 868 function ad_nodeapi(&$node, $op, $teaser, $page) {
pierre@0 869 global $user;
pierre@0 870
pierre@0 871 switch ($op) {
pierre@0 872
pierre@0 873 case 'load':
pierre@0 874 $ad = db_fetch_array(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid));
pierre@0 875 $merge = array_merge((array)$node, (array)$ad);
pierre@0 876 $adtype = module_invoke('ad_'. $ad['adtype'], 'adapi', 'load', $merge);
pierre@0 877 if (is_array($adtype)) {
pierre@0 878 return array_merge($ad, $adtype);
pierre@0 879 }
pierre@0 880 else {
pierre@0 881 return $ad;
pierre@0 882 }
pierre@0 883 break;
pierre@0 884
pierre@0 885 case 'insert':
pierre@0 886 if (isset($node->adtype)) {
pierre@0 887 if ($node->status != 1 && $node->adstatus == 'active') {
pierre@1 888 $node->adstatus = 'expired';
pierre@0 889 }
pierre@0 890 $activated = $node->adstatus == 'active' ? time() : 0;
pierre@1 891 if (!isset($node->autoactivate)) {
pierre@0 892 $node->autoactivate = 0;
pierre@0 893 }
pierre@0 894 if (!isset($node->maxviews)) {
pierre@0 895 $node->maxviews = 0;
pierre@0 896 }
pierre@0 897 if (!isset($node->maxclicks)) {
pierre@0 898 $node->maxclicks = 0;
pierre@0 899 }
pierre@0 900 db_query("INSERT INTO {ads} (aid, uid, adstatus, adtype, redirect, autoactivate, autoexpire, activated, maxviews, maxclicks) VALUES(%d, %d, '%s', '%s', '%s', %d, %d, %d, %d, %d)", $node->nid, $node->uid, $node->adstatus, $node->adtype, url('ad/redirect/'. $node->nid, array('absolute' => TRUE)), $node->autoactivate ? strtotime($node->autoactivate) : '', $node->autoexpire ? strtotime($node->autoexpire) : '', $activated, $node->maxviews, $node->maxclicks);
pierre@0 901 ad_statistics_increment($node->nid, 'create');
pierre@0 902 }
pierre@0 903 break;
pierre@0 904
pierre@0 905 case 'update':
pierre@0 906 if (isset($node->adtype)) {
pierre@0 907 $ad = db_fetch_object(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid));
pierre@0 908 // Ad must be in approved state to be able to autoactivate it.
pierre@1 909 if ($node->adstatus != 'approved' && isset($node->autoactive) && $node->autoactivate) {
pierre@0 910 if ($node->adstatus == 'active') {
pierre@0 911 // This ad is already active, no need to autoactivate it.
pierre@0 912 $node->autoactivate = 0;
pierre@0 913 }
pierre@0 914 else {
pierre@0 915 drupal_set_message(t('This ad will not be automatically activated at the scheduled time because it is not in the <em>approved</em> state.'), 'error');
pierre@0 916 }
pierre@0 917 }
pierre@0 918 // If this node has been upublished, the ad should no longer be active.
pierre@0 919 if ($node->status != 1 && $node->adstatus == 'active') {
pierre@1 920 $node->adstatus = 'expired';
pierre@0 921 }
pierre@0 922 // Check if ad is being manually activated.
pierre@0 923 if ($ad->adstatus != 'active' && $node->adstatus == 'active') {
pierre@0 924 $activated = time();
pierre@0 925 }
pierre@0 926 // Check if ad is being manually expired.
pierre@0 927 else if ($ad->adstatus != 'expired' && $node->adstatus == 'expired') {
pierre@0 928 // Ad has been manually expired.
pierre@1 929 $activated = $ad->activated;
pierre@0 930 $expired = time();
pierre@0 931 }
pierre@0 932 // Ad has not been manually activated or expired, preserve timestamps.
pierre@0 933 else {
pierre@0 934 $activated = $ad->activated;
pierre@0 935 $expired = $ad->expired;
pierre@0 936 }
pierre@0 937 // Ad status has changed, record the event.
pierre@0 938 if ($ad->adstatus != $node->adstatus) {
pierre@0 939 ad_statistics_increment($node->nid, $node->adstatus);
pierre@0 940 }
pierre@0 941 // Update ads table with new information.
pierre@1 942 db_query("UPDATE {ads} SET uid = %d, adstatus = '%s', adtype = '%s', redirect = '%s', autoactivate = %d, autoexpire = %d, activated = %d, maxviews = %d, maxclicks = %d, expired = %d WHERE aid = %d", $node->uid, $node->adstatus, $node->adtype, url('ad/redirect/'. $node->nid, array('absolute' => TRUE)), isset($node->autoactivate) && strlen($node->autoactivate) > 1 ? strtotime($node->autoactivate) : '', isset($node->autoexpire) && strlen($node->autoexpire) > 1 ? strtotime($node->autoexpire) : '', isset($activated) ? $activated : 0, isset($node->maxviews) ? (int)$node->maxviews : 0, isset($node->maxclicks) ? (int)$node->maxclicks : 0, isset($expired) ? $expired : 0, $node->nid);
pierre@0 943 ad_statistics_increment($node->nid, 'update');
pierre@0 944 }
pierre@0 945 break;
pierre@0 946
pierre@0 947 case 'delete':
pierre@0 948 db_query("DELETE FROM {ads} WHERE aid = %d", $node->nid);
pierre@0 949 db_query("DELETE FROM {ad_statistics} WHERE aid = %d", $node->nid);
pierre@0 950 // All that's left of the ad is a single timestamp as to when it was
pierre@0 951 // deleted.
pierre@0 952 ad_statistics_increment($node->nid, 'delete');
pierre@0 953 break;
pierre@0 954
pierre@0 955 case 'view':
pierre@0 956 if (isset($node->adtype)) {
sly@3 957 if (variable_get('ad_meta_noindex', 1)) {
sly@3 958 ad_noindex_meta();
sly@3 959 }
pierre@0 960 $node = node_prepare($node, $teaser);
pierre@0 961 $node->content['body'] = array(
pierre@0 962 '#value' => $teaser ? $node->teaser : theme('node_ad', $node, $page),
pierre@0 963 '#weight' => 1,
pierre@0 964 );
pierre@0 965 }
pierre@0 966 break;
pierre@0 967 }
pierre@0 968 // Allow ad type module to act on nodeapi events. The adapi hook provides
pierre@0 969 // access to additional variables not available in the nodeapi hook.
pierre@0 970 if (isset($node->adtype)) {
pierre@0 971 // Don't use module_invoke, as in pre-PHP5 the changes to $node won't be
pierre@0 972 // passed back.
pierre@0 973 $function = "ad_$node->adtype" .'_adapi';
pierre@0 974 if (function_exists($function)) {
pierre@0 975 $function($op, $node);
pierre@0 976 }
pierre@0 977 }
pierre@0 978 // Allow ad cache module to act on nodeapi events.
pierre@0 979 $cache = variable_get('ad_cache', 'none');
pierre@0 980 if ($cache != 'none') {
pierre@0 981 $function = "ad_cache_$cache" .'_adcacheapi';
pierre@0 982 if (function_exists($function)) {
pierre@0 983 $function($op, $node);
pierre@0 984 }
pierre@0 985 }
pierre@1 986
pierre@1 987 // Rebuild the cache after all hooks are invoked.
pierre@1 988 switch ($op) {
pierre@1 989 case 'insert':
pierre@1 990 case 'update':
pierre@1 991 case 'delete':
pierre@1 992 if (variable_get('ad_cache_file_rebuild_realtime', 0) &&
pierre@1 993 isset($node->adtype)) {
pierre@1 994 ad_rebuild_cache();
pierre@1 995 }
pierre@1 996 }
pierre@0 997 }
pierre@0 998
sly@3 999 /**
sly@3 1000 * Add the noindex meta tag.
sly@3 1001 */
sly@3 1002 function ad_noindex_meta() {
sly@3 1003 static $added = FALSE;
sly@3 1004 if (!$added) {
sly@3 1005 drupal_set_html_head('<meta name="robots" content="noindex" />');
sly@3 1006 $added = TRUE;
sly@3 1007 }
sly@3 1008 }
sly@3 1009
pierre@0 1010 function ad_adapi($op, $node = NULL) {
pierre@0 1011 switch ($op) {
pierre@0 1012 case 'permissions':
pierre@1 1013 return array(
pierre@1 1014 'access statistics' => TRUE,
pierre@1 1015 'access click history' => TRUE,
pierre@1 1016 'set status as pending' => FALSE,
pierre@1 1017 'set status as denied' => FALSE,
pierre@1 1018 'set status from pending to approved' => FALSE,
pierre@1 1019 'set status from pending to denied' => FALSE,
pierre@1 1020 'set status from approved to active' => TRUE,
pierre@1 1021 'set status from approved to offline' => TRUE,
pierre@1 1022 'set status from active to offline' => TRUE,
pierre@1 1023 'set status from active to expired' => FALSE,
pierre@1 1024 'set status from offline to active' => TRUE,
pierre@1 1025 'set status from offline to expired' => FALSE,
pierre@1 1026 );
pierre@0 1027 break;
pierre@0 1028 }
pierre@0 1029 }
pierre@0 1030
pierre@0 1031 /**
pierre@0 1032 * Implementation of hook_menu().
pierre@0 1033 */
pierre@0 1034 function ad_menu() {
pierre@0 1035 $items = array();
pierre@0 1036
pierre@0 1037 $items['admin/content/ad'] = array(
pierre@0 1038 'title' => 'Ads',
pierre@0 1039 'page callback' => 'ad_admin_list',
pierre@0 1040 'access arguments' => array('administer advertisements'),
pierre@0 1041 'description' => 'Configure and manage your advertising system.',
pierre@0 1042 'file' => 'ad.admin.inc',
pierre@0 1043 );
pierre@0 1044 $items['admin/content/ad/list'] = array(
pierre@0 1045 'title' => 'List',
pierre@0 1046 'page callback' => 'ad_admin_list',
pierre@0 1047 'access arguments' => array('administer advertisements'),
pierre@0 1048 'type' => MENU_DEFAULT_LOCAL_TASK,
pierre@0 1049 'file' => 'ad.admin.inc',
pierre@0 1050 );
pierre@0 1051 $items['admin/content/ad/configure'] = array(
pierre@0 1052 'title' => 'Settings',
pierre@0 1053 'page callback' => 'drupal_get_form',
pierre@0 1054 'page arguments' => array('ad_admin_configure_settings'),
pierre@0 1055 'access arguments' => array('administer advertisements'),
pierre@0 1056 'type' => MENU_LOCAL_TASK,
pierre@0 1057 'weight' => 3,
pierre@0 1058 'file' => 'ad.admin.inc',
pierre@0 1059 );
pierre@1 1060 $items['node/add/ad/ahah'] = array(
pierre@1 1061 'access arguments' => array('create advertisements'),
pierre@1 1062 'page callback' => 'ad_form_ahah',
pierre@1 1063 'type' => MENU_CALLBACK,
pierre@1 1064 );
pierre@0 1065
pierre@0 1066 ad_menu_add_global_settings($items);
pierre@0 1067
pierre@0 1068 $items['admin/content/ad/groups'] = array(
pierre@0 1069 'title' => 'Ad groups',
pierre@0 1070 'page callback' => 'ad_admin_groups_list',
pierre@0 1071 'access arguments' => array('administer advertisements'),
pierre@0 1072 'type' => MENU_LOCAL_TASK,
pierre@0 1073 'weight' => 5,
pierre@0 1074 'file' => 'ad.admin.inc',
pierre@0 1075 );
pierre@0 1076 $items['admin/content/ad/groups/list'] = array(
pierre@0 1077 'title' => 'List',
pierre@0 1078 'page callback' => 'ad_admin_groups_list',
pierre@0 1079 'access arguments' => array('administer advertisements'),
pierre@0 1080 'type' => MENU_DEFAULT_LOCAL_TASK,
pierre@0 1081 'weight' => 0,
pierre@0 1082 'file' => 'ad.admin.inc',
pierre@0 1083 );
pierre@0 1084 $items['admin/content/ad/groups/add'] = array(
pierre@0 1085 'title' => 'Create group',
pierre@0 1086 'page callback' => 'drupal_get_form',
pierre@0 1087 'page arguments' => array('ad_admin_group_form'),
pierre@0 1088 'access arguments' => array('administer advertisements'),
pierre@0 1089 'type' => MENU_LOCAL_TASK,
pierre@0 1090 'weight' => 3,
pierre@0 1091 'file' => 'ad.admin.inc',
pierre@0 1092 );
pierre@0 1093 $items["admin/content/ad/groups/%ad_group/edit"] = array(
pierre@0 1094 'title' => 'Edit group',
pierre@0 1095 'page callback' => 'drupal_get_form',
pierre@0 1096 'page arguments' => array('ad_admin_group_form', 4),
pierre@0 1097 'access arguments' => array('administer advertisements'),
pierre@0 1098 'weight' => 1,
pierre@0 1099 'file' => 'ad.admin.inc',
pierre@0 1100 );
pierre@0 1101 $items["admin/content/ad/groups/%ad_group/delete"] = array(
pierre@0 1102 'title' => 'Delete group',
pierre@0 1103 'page callback' => 'drupal_get_form',
pierre@0 1104 'page arguments' => array('ad_confirm_group_delete', 4),
pierre@0 1105 'access arguments' => array('administer advertisements'),
pierre@0 1106 'weight' => 2,
pierre@0 1107 'file' => 'ad.admin.inc',
pierre@0 1108 );
pierre@0 1109 $items['admin/content/ad/configure/global'] = array(
pierre@0 1110 'title' => 'Global settings',
pierre@0 1111 'page callback' => 'drupal_get_form',
pierre@0 1112 'page arguments' => array('ad_admin_configure_settings'),
pierre@0 1113 'access arguments' => array('administer advertisements'),
pierre@0 1114 'type' => MENU_DEFAULT_LOCAL_TASK,
pierre@0 1115 'weight' => 0,
pierre@0 1116 'file' => 'ad.admin.inc',
pierre@0 1117 );
pierre@0 1118 $items["node/%node/details/%"] = array(
pierre@0 1119 'title' => 'Click details',
pierre@0 1120 'page callback' => 'ad_click_details',
pierre@0 1121 'page arguments' => array(1, 3),
pierre@0 1122 'access arguments' => array(1, 'access click history'),
pierre@1 1123 'access callback' => 'ad_permission',
pierre@0 1124 'type' => MENU_CALLBACK,
pierre@0 1125 'file' => 'ad.pages.inc',
pierre@0 1126 );
pierre@1 1127 $items["ad/redirect/%"] = array(
pierre@0 1128 'access arguments' => array('show advertisements'),
pierre@0 1129 'type' => MENU_CALLBACK,
pierre@0 1130 'page callback' => 'ad_redirect',
pierre@1 1131 'page arguments' => (array(2)),
pierre@0 1132 );
pierre@0 1133
pierre@0 1134 return $items;
pierre@0 1135 }
pierre@0 1136
pierre@0 1137 /**
pierre@0 1138 * Load settings for all ad modules. Those modules, who don't
pierre@0 1139 * have their settings form, will get a standard one.
pierre@0 1140 */
pierre@0 1141 function ad_menu_add_global_settings(&$menu_items) {
pierre@0 1142 $adtypes = ad_get_types();
pierre@0 1143 foreach ($adtypes as $type => $name) {
pierre@0 1144 // Ad type global settings.
pierre@0 1145 $settings = 'ad_'. $type .'_global_settings';
pierre@1 1146 $file = 'ad_image.module';
pierre@0 1147 if (!function_exists($settings)) {
pierre@0 1148 $settings = 'ad_no_global_settings';
pierre@1 1149 $file = 'ad.admin.inc';
pierre@0 1150 }
pierre@0 1151 $menu_items['admin/content/ad/configure/'. $type] = array(
pierre@0 1152 'title' => $name,
pierre@0 1153 'page callback' => 'drupal_get_form',
pierre@0 1154 'page arguments' => array($settings),
pierre@0 1155 'access arguments' => array('administer advertisements'),
pierre@0 1156 'type' => MENU_LOCAL_TASK,
pierre@0 1157 'weight' => 2,
pierre@0 1158 'file' => 'ad.admin.inc',
pierre@0 1159 );
pierre@0 1160 }
pierre@0 1161 }
pierre@0 1162
pierre@0 1163 /**
pierre@0 1164 * Drupal menu wildcard Ad group loader
pierre@0 1165 */
pierre@0 1166 function ad_group_load($tid) {
pierre@0 1167 if (!is_numeric($tid)) {
pierre@0 1168 return FALSE;
pierre@0 1169 }
pierre@0 1170 $group = ad_groups_list(TRUE, $tid);
pierre@0 1171 if (!isset($group)) {
pierre@0 1172 return FALSE;
pierre@0 1173 }
pierre@0 1174 return $group;
pierre@0 1175 }
pierre@0 1176
pierre@0 1177 /**
pierre@0 1178 * Implementation of hook_block().
pierre@0 1179 */
pierre@0 1180 function ad_block($op = 'list', $delta = 0, $edit = array()) {
pierre@0 1181 switch ($op) {
pierre@0 1182 case 'list':
pierre@0 1183 $blocks = array();
pierre@0 1184 $groups = ad_groups_list();
pierre@0 1185 foreach ($groups as $tid => $name) {
pierre@0 1186 $blocks[$tid]['info'] = t('ad group: @name', array('@name' => $name));
pierre@0 1187 }
pierre@0 1188 return $blocks;
pierre@0 1189 case 'configure':
pierre@0 1190 $form['ad_block_quantity_'. $delta] = array(
pierre@0 1191 '#type' => 'select',
pierre@0 1192 '#title' => t('Number of ads'),
pierre@0 1193 '#default_value' => variable_get('ad_block_quantity_'. $delta, 1),
pierre@0 1194 '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25)),
pierre@0 1195 '#description' => t('Select the maximum number of unique ads that should be displayed together in this block. If you specify a number larger than the maximum number of ads in this ad group, all ads will be displayed once.'),
pierre@0 1196 );
pierre@0 1197 return $form;
pierre@0 1198 case 'save':
pierre@0 1199 variable_set('ad_block_quantity_'. $delta, $edit['ad_block_quantity_'. $delta]);
pierre@0 1200 break;
pierre@0 1201 case 'view':
pierre@0 1202 $groups = ad_groups_list();
pierre@0 1203 $block['content'] = ad($delta, variable_get('ad_block_quantity_'. $delta, 1));
pierre@0 1204 return $block;
pierre@0 1205 }
pierre@0 1206 }
pierre@0 1207
pierre@0 1208 /**
pierre@0 1209 * Determine whether the user has a given privilege.
pierre@0 1210 *
pierre@1 1211 * @param $aid
pierre@1 1212 * ID of advertisement.
pierre@0 1213 * @param $permission
pierre@1 1214 * Permission string which should be checked (such as 'access click history')
pierre@0 1215 * @param $account
pierre@0 1216 * User object, which are accessing the ad or current user by default.
pierre@0 1217 */
pierre@1 1218 function ad_permission($aid, $string, $account = NULL) {
pierre@0 1219 global $user;
pierre@1 1220 $access = FALSE;
pierre@0 1221
pierre@1 1222 // by default, check permission for current user
pierre@0 1223 if (!isset($account)) {
pierre@0 1224 $account = $user;
pierre@0 1225 }
pierre@0 1226
pierre@1 1227 // user #1 has all privileges
pierre@0 1228 if ($account->uid == 1) {
pierre@0 1229 return TRUE;
pierre@0 1230 }
pierre@0 1231
pierre@1 1232 // if you have administer permissions, you have all permissions
pierre@0 1233 if (user_access('administer advertisements', $account)) {
pierre@0 1234 return TRUE;
pierre@0 1235 }
pierre@0 1236
pierre@1 1237 // when used in the Drupal menu, $aid may be the full ad object.
pierre@1 1238 if (is_object($aid) && isset($aid->aid)) {
pierre@1 1239 $aid = $aid->aid;
pierre@1 1240 }
sly@3 1241 else if (is_object($aid) && isset($aid->nid)) {
sly@3 1242 $aid = $aid->nid;
sly@3 1243 }
pierre@1 1244 else if (is_object($aid)) {
pierre@1 1245 watchdog('ad', 'Invalid aid object passed into ad_permission, no aid->aid set.');
pierre@1 1246 $aid = 0;
pierre@0 1247 }
pierre@0 1248
pierre@1 1249 // invoke ad_owners module to determine user's access
pierre@1 1250 if (module_exists('ad_owners') &&
pierre@1 1251 function_exists('ad_owners_permission')) {
pierre@1 1252 $access = ad_owners_permission($aid, $string, $account);
pierre@1 1253 }
pierre@1 1254 // no ad_owners module, allow acces to statistics and click history
pierre@1 1255 else if (in_array($string, array('access statistics', 'access click history'))) {
pierre@1 1256 $access = TRUE;
pierre@1 1257 }
pierre@1 1258 // with no ad_owners module, all other permissions are denied unless user
pierre@1 1259 // has 'administer advertisements' permission
pierre@1 1260 return $access;
pierre@0 1261 }
pierre@0 1262
pierre@0 1263 /**
pierre@0 1264 * Returns ad types data.
pierre@0 1265 *
pierre@0 1266 * @param $op
pierre@0 1267 * If set to 'name', will only return array of type names ($type => $name).
pierre@0 1268 * If set to 'data', will return all of the type's data
pierre@0 1269 * @param $type
pierre@0 1270 * If not specified, will return array of all available types, else will
pierre@0 1271 * return specific type's name or data.
pierre@0 1272 */
pierre@0 1273 function ad_get_types($op = 'name', $type = NULL) {
pierre@0 1274 $adtypes = module_invoke_all('adapi', 'type', array());
pierre@0 1275 switch ($op) {
pierre@0 1276 case 'name':
pierre@0 1277 if (isset($type)) {
pierre@0 1278 return $adtypes[$type]['name'];
pierre@0 1279 }
pierre@0 1280 else {
pierre@0 1281 foreach ($adtypes as $type => $data) {
pierre@0 1282 $adtypes[$type] = $data['name'];
pierre@0 1283 }
pierre@0 1284 return $adtypes;
pierre@0 1285 }
pierre@0 1286 case 'data':
pierre@0 1287 if (isset($type)) {
pierre@0 1288 return $adtypes[$type];
pierre@0 1289 }
pierre@0 1290 else {
pierre@0 1291 return $adtypes;
pierre@0 1292 }
pierre@0 1293 }
pierre@0 1294 }
pierre@0 1295
pierre@0 1296 /**
pierre@0 1297 * Return an array of all groups, or a specific group.
pierre@0 1298 *
pierre@0 1299 * @param $object
pierre@0 1300 * If FALSE, will return only name of group(s). If TRUE, will return full
pierre@0 1301 * group object including ->name, ->description, and ->tid.
pierre@0 1302 * @param $tid
pierre@0 1303 * If set to an integer >0, will only return group info about that specific
pierre@0 1304 * group.
pierre@0 1305 */
pierre@0 1306 function ad_groups_list($object = FALSE, $tid = NULL) {
pierre@0 1307 static $groups = array();
pierre@0 1308 static $names = array();
pierre@0 1309
pierre@0 1310 // Return the full group object(s).
pierre@0 1311 if ($object) {
pierre@0 1312 if (empty($groups)) {
pierre@0 1313 $tids = taxonomy_get_tree(_ad_get_vid());
pierre@0 1314 if (is_array($tids)) {
pierre@0 1315 foreach ($tids as $group) {
pierre@0 1316 $groups[$group->tid]->name = $group->name;
pierre@0 1317 $groups[$group->tid]->description = $group->description;
pierre@0 1318 $groups[$group->tid]->tid = $group->tid;
pierre@0 1319 $groups[$group->tid]->weight = $group->weight;
pierre@0 1320 }
pierre@0 1321 }
pierre@0 1322 // Hard coded "default" group with tid of 0.
pierre@0 1323 $groups[0]->name = t('default');
pierre@0 1324 $groups[0]->description = t('The default ad group is comprised of all ads not assigned to any other ad group.');
pierre@0 1325 $groups[0]->tid = 0;
pierre@0 1326 $groups[0]->weight = 0;
pierre@0 1327 }
pierre@0 1328 // Return a specific group object.
pierre@0 1329 if ((int)$tid) {
pierre@0 1330 return $groups[$tid];
pierre@0 1331 }
pierre@0 1332 // Return an array of all group objects.
pierre@0 1333 else {
pierre@0 1334 return $groups;
pierre@0 1335 }
pierre@0 1336 }
pierre@0 1337 // Return only the group name(s).
pierre@0 1338 else {
pierre@0 1339 if (empty($names)) {
pierre@0 1340 $tids = taxonomy_get_tree(_ad_get_vid());
pierre@0 1341 if (is_array($tids)) {
pierre@0 1342 foreach ($tids as $group) {
pierre@0 1343 $names[$group->tid] = $group->name;
pierre@0 1344 }
pierre@0 1345 }
pierre@0 1346 // Hard coded "default" group with tid of 0.
pierre@0 1347 $names[0] = t('default');
pierre@0 1348 }
pierre@0 1349 // Return a specific group name.
pierre@0 1350 if ((int)$tid) {
pierre@0 1351 return $names[$tid];
pierre@0 1352 }
pierre@0 1353 // Return an array of all group names.
pierre@0 1354 else {
pierre@0 1355 return $names;
pierre@0 1356 }
pierre@0 1357 }
pierre@0 1358 }
pierre@0 1359
pierre@0 1360 /**
pierre@0 1361 * Implement ad notify api _hook.
pierre@0 1362 */
pierre@0 1363 function ad_adnotifyapi($op, $arg1 = NULL, $arg2 = NULL) {
pierre@0 1364 switch ($op) {
pierre@0 1365 // Make the following events available for notification.
pierre@0 1366 case 'register':
pierre@0 1367 return array(
pierre@0 1368 '-expired' => t('Email @when before the advertisement will expire.'),
pierre@0 1369 'expired' => t('Email @when after the advertisement is expired.'),
pierre@0 1370 '-active' => t('Email @when before the advertisement will be activated (if scheduled).'),
pierre@0 1371 'active' => t('Email @when after the advertisement is activated.'),
sly@2 1372 'offline' => t('Email @when after the advertisement is taken offline.'),
pierre@0 1373 'click' => t('Email @when after the advertisement is clicked.'),
pierre@0 1374 'approved' => t('Email @when after the advertisement is approved.'),
pierre@0 1375 'denied' => t('Email @when after the advertisement is denied.'),
sly@2 1376 'update' => t('Email @when after the advertisement is updated.'),
pierre@0 1377 );
pierre@0 1378 break;
pierre@0 1379 case '-expired':
pierre@0 1380 $node = node_load($arg1->aid);
pierre@0 1381 if (isset($node->autoexpire) && $node->autoexpire) {
pierre@0 1382 if ((time() + $arg1->delay >= $node->autoexpire) &&
pierre@0 1383 ($arg1->sent + $arg1->delay < $node->autoexpire)) {
pierre@0 1384 return array('-expired' => 1);
pierre@0 1385 }
pierre@0 1386 }
pierre@0 1387 break;
pierre@0 1388 case '-active':
pierre@0 1389 $node = node_load($arg1->aid);
pierre@0 1390 if (isset($node->autoactivate) && $node->autoactivate) {
pierre@0 1391 if ((time() + $arg1->delay >= $node->autoactivate) &&
pierre@0 1392 ($arg1->sent + $arg1->delay < $node->autoactivate)) {
pierre@0 1393 return array('-active' => 1);
pierre@0 1394 }
pierre@0 1395 }
pierre@0 1396 break;
pierre@0 1397 case 'mail_text':
pierre@0 1398 switch ($arg1) {
pierre@0 1399 case 'expired':
pierre@0 1400 return array(
pierre@1 1401 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1402 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" that was being displayed on the %site-name website has expired.\n\n Your advertisement was viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
pierre@0 1403 );
pierre@0 1404 case '-expired':
pierre@0 1405 return array(
pierre@1 1406 'subject' => t('[%site-name ad] expiration notification'),
pierre@1 1407 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" that is being displayed on the %site-name website will expire on %autoexpire_large.\n\n Your advertisement has been viewed %today_impressions times and clicked %today_clicks times today. It was viewed %yesterday_impressions times and clicked %yesterday_clicks times yesterday. It has been viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
pierre@0 1408 );
pierre@0 1409 case 'active':
pierre@0 1410 return array(
pierre@1 1411 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1412 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" is now actively being displayed on the %site-name website.\n\n Your advertisement has been viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
pierre@0 1413 );
pierre@0 1414 case '-active':
pierre@0 1415 return array(
pierre@1 1416 'subject' => t('[%site-name ad] activation notification'),
pierre@1 1417 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" will be actively displayed on the %site-name website on %autoactivate_large.\n\n You can view statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
pierre@0 1418 );
pierre@0 1419 case 'click':
pierre@0 1420 return array(
pierre@1 1421 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1422 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been clicked.\n\n Your advertisement has been viewed %today_impressions times and clicked %today_clicks times today. It was viewed %yesterday_impressions times and clicked %yesterday_clicks times yesterday. It has been viewed %global_impressions times and clicked %global_clicks times since it was activated on %activated_large.\n\n You will receive this %frequency You can view additional statistics about this advertisement or update this notification at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
pierre@0 1423 );
pierre@0 1424 case 'approved':
pierre@0 1425 return array(
pierre@1 1426 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1427 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been approved.\n\n You can view statistics about this advertisement at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
pierre@0 1428 );
pierre@0 1429 case 'denied':
pierre@0 1430 return array(
pierre@1 1431 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1432 'body' => t("Hello %owner_name,\n\n This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been denied and will not be displayed.\n\n You can view statistics about this advertisement at the following url:\n %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
pierre@0 1433 );
pierre@0 1434 }
pierre@0 1435 break;
pierre@0 1436 }
pierre@0 1437 }
pierre@0 1438
pierre@0 1439 function _ad_check_installation() {
pierre@0 1440 // Verify serve.php exists and is readable.
pierre@0 1441 $adserve = variable_get('adserve', '');
pierre@0 1442 $adserveinc = variable_get('adserveinc', '');
pierre@0 1443 if (!file_exists($adserve)) {
pierre@0 1444 // The serve.php file should be in the same directory as the ad.module.
pierre@0 1445 $adserve = drupal_get_path('module', 'ad') .'/serve.php';
pierre@0 1446 variable_set('adserve', $adserve);
pierre@0 1447 }
pierre@0 1448 if (!is_readable($adserve)) {
pierre@0 1449 variable_set('adserve', '');
pierre@0 1450 drupal_set_message(t('Failed to read the required file %filename. Please make the file readable by the webserver process. No ads can be displayed until this problem is resolved.', array('%filename' => $adserve)), 'error');
pierre@0 1451 }
pierre@0 1452 if (!file_exists($adserveinc)) {
pierre@0 1453 // The adserve.inc file should be in the same directory as the ad.module.
pierre@0 1454 $adserveinc = drupal_get_path('module', 'ad') .'/adserve.inc';
pierre@0 1455 variable_set('adserveinc', $adserveinc);
pierre@0 1456 }
pierre@0 1457 if (!is_readable($adserveinc)) {
pierre@0 1458 variable_set('adserveinc', '');
pierre@0 1459 drupal_set_message(t('Failed to read the required file %filename. Please make the file readable by the webserver process. No ads can be displayed until this problem is resolved.', array('%filename' => $adserveinc)), 'error');
pierre@0 1460 }
pierre@0 1461
pierre@0 1462 // Validate vid in vocabulary table.
pierre@0 1463 $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = 'ad'"));
pierre@0 1464 if ($vid != variable_get('ad_group_vid', '')) {
pierre@0 1465 drupal_set_message(t('Invalid vocabulary defined for advertisements, attempting to auto-fix.'), 'error');
pierre@0 1466 if ($vid) {
pierre@0 1467 db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid', ''));
pierre@0 1468 variable_set('ad_group_vid_restore', variable_get('ad_group_vid', ''));
pierre@0 1469 }
pierre@0 1470 variable_del('ad_group_vid');
pierre@0 1471 }
pierre@0 1472 else {
pierre@0 1473 // Validate vid in vocabulary_node_types table.
pierre@0 1474 $result = db_query("SELECT vid FROM {vocabulary_node_types} WHERE type = 'ad'");
pierre@0 1475 $found = FALSE;
pierre@0 1476 while ($vocab = db_fetch_object($result)) {
pierre@0 1477 if ($vocab->vid == variable_get('ad_group_vid', '')) {
pierre@0 1478 $found = TRUE;
pierre@0 1479 }
pierre@0 1480 }
pierre@0 1481 if (!$found) {
pierre@0 1482 drupal_set_message(t('Missing vocabulary node type for advertisements, attempting to auto-fix.'), 'error');
pierre@0 1483 db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid', ''));
pierre@0 1484 db_query("DELETE FROM {vocabulary} WHERE vid = %d", variable_get('ad_group_vid', ''));
pierre@0 1485 variable_set('ad_group_vid_restore', variable_get('ad_group_vid', ''));
pierre@0 1486 variable_del('ad_group_vid');
pierre@0 1487 }
pierre@0 1488 }
pierre@0 1489
pierre@0 1490 _ad_get_vid();
pierre@0 1491 // Preserve old ad groups, if any.
pierre@0 1492 if (($old = variable_get('ad_group_vid_restore', '')) &&
pierre@0 1493 $vid = variable_get('ad_group_vid', '')) {
pierre@0 1494 drupal_set_message(t('Restoring orphaned ad group configuration.'));
pierre@0 1495 db_query('UPDATE {term_data} SET vid = %d WHERE vid = %d', $vid, $old);
pierre@0 1496 variable_set('ad_group_vid_restore', '');
pierre@0 1497 }
pierre@0 1498
pierre@0 1499 $rid = db_result(db_query_range("SELECT rid FROM {permission} WHERE perm LIKE '%%show advertisements%%'", 1));
pierre@0 1500 if (!$rid) {
pierre@0 1501 drupal_set_message(t('Be sure to enable "!show" permissions for all roles that you wish to see advertisements.', array('!show' => l(t('show advertisements'), 'admin/user/permissions'))));
pierre@0 1502 }
pierre@0 1503
pierre@0 1504 // Allow modules to define an action to take each time an ad is served.
pierre@0 1505 // When modules define 'adserve_select' or 'adserve_filter', they must set
pierre@0 1506 // the 'function' and 'path' parameters. The 'weight' parameter can
pierre@0 1507 // optionally be set.
pierre@0 1508 // function: the function to call when serving an add
pierre@0 1509 // path: the path to the include file where $function is defined
pierre@0 1510 // Modules can define actions that happen when advertisements are served.
pierre@0 1511 // Currently support actions are:
pierre@0 1512 // - init_text (display content before displaying ads) // TODO
pierre@0 1513 // - select (alter which ads are selected to be displayed) // TODO
pierre@0 1514 // - filter (filter selected ads before they are displayed) // TODO
pierre@0 1515 // - exit_text (display content after displaying ads) // TODO
pierre@0 1516 $hooks = array('init_text', 'select', 'filter', 'exit_text');
pierre@0 1517 foreach ($hooks as $hook) {
pierre@0 1518 $adserve_actions = module_invoke_all('adapi', "adserve_$hook", array());
pierre@0 1519 $actions = array();
pierre@0 1520 foreach ($adserve_actions as $name => $action) {
pierre@0 1521 if (is_numeric($action['weight'])) {
pierre@0 1522 $weight = $action['weight'];
pierre@0 1523 }
pierre@0 1524 else {
pierre@0 1525 // weight is an optional, defaults to 0
pierre@0 1526 $weight = $action['weight'] = 0;
pierre@0 1527 }
pierre@0 1528 $actions[$weight .'.'. $name] = $action;
pierre@0 1529 $actions[$weight .'.'. $name]['name'] = $name;
pierre@0 1530 }
pierre@0 1531 // order actions by weight (multiple same-weight actions sorted by alpha)
pierre@0 1532 ksort($actions);
pierre@0 1533 variable_set("adserve_$hook", serialize($actions));
pierre@0 1534 }
pierre@0 1535
pierre@0 1536 module_invoke_all('adapi', 'check_install', array());
pierre@0 1537 }
pierre@0 1538
pierre@0 1539 /**
pierre@0 1540 * Creates a vocabulary for use by ad groups if not already created.
pierre@0 1541 */
pierre@0 1542 function _ad_get_vid() {
pierre@0 1543 $vid = variable_get('ad_group_vid', '');
pierre@0 1544 if (empty($vid)) {
pierre@0 1545 // No vid stored in the variables table, check if one even exists.
pierre@0 1546 $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = '%s'", 'ad'));
pierre@0 1547 if (!$vid) {
pierre@0 1548 // No vid, so we create one.
pierre@0 1549 $edit = array(
pierre@0 1550 'name' => t('Ad groups'),
pierre@0 1551 'multiple' => 1,
pierre@0 1552 'required' => 0,
pierre@0 1553 'hierarchy' => 0,
pierre@0 1554 'relations' => 0,
pierre@0 1555 'module' => 'ad',
pierre@0 1556 'nodes' => array('ad' => 1)
pierre@0 1557 );
pierre@0 1558
pierre@0 1559 taxonomy_save_vocabulary($edit);
pierre@0 1560 $vid = $edit['vid'];
pierre@0 1561 }
pierre@0 1562 // Save the vid for next time.
pierre@0 1563 variable_set('ad_group_vid', $vid);
pierre@0 1564 }
pierre@0 1565 return $vid;
pierre@0 1566 }
pierre@0 1567
pierre@0 1568 /**
pierre@0 1569 * Builds the necessary HTML to display an image-based impressions counter.
pierre@0 1570 */
sly@2 1571 function ad_display_image($aid, $css = TRUE) {
pierre@0 1572 global $base_url;
pierre@0 1573 $adserve = variable_get('adserve', '');
pierre@0 1574 $cache = variable_get('ad_cache', 'none');
pierre@0 1575 $variables = "?o=image";
sly@2 1576 $variables .= "&a=$aid";
sly@2 1577 if ($cache != 'none') {
sly@2 1578 $variables .= '&c='. $cache . module_invoke('ad_cache_'. $cache, 'adcacheapi', 'display_variables', array());
pierre@0 1579 }
sly@2 1580 $output = '<img src="'. htmlentities(url($base_url .'/'. $adserve . $variables)) .'" height="0" width="0" alt="view counter" />';
pierre@0 1581 if ($css) {
pierre@0 1582 return '<div class="ad-image-counter">'. $output .'</div>';
pierre@0 1583 }
pierre@0 1584 else {
pierre@0 1585 return $output;
pierre@0 1586 }
pierre@0 1587 }
pierre@0 1588
pierre@0 1589 /**
pierre@0 1590 * Retrieve the group name from the nid.
pierre@0 1591 */
pierre@0 1592 function _ad_get_group($nid) {
pierre@0 1593 static $groups = array();
pierre@0 1594
pierre@0 1595 if (!isset($groups[$nid])) {
pierre@0 1596 $result = db_query('SELECT d.name FROM {term_data} d LEFT JOIN {term_node} n ON d.tid = n.tid WHERE n.nid = %d AND d.vid = %d', $nid, _ad_get_vid());
pierre@0 1597 while ($term = db_fetch_object($result)) {
pierre@0 1598 $terms[] = $term->name;
pierre@0 1599 }
pierre@0 1600 if (!empty($terms)) {
pierre@0 1601 $groups[$nid] = implode(', ', $terms);
pierre@0 1602 }
pierre@0 1603 else {
pierre@0 1604 $groups[$nid] = t('default');
pierre@0 1605 }
pierre@0 1606 }
pierre@0 1607
pierre@0 1608 return $groups[$nid];
pierre@0 1609 }
pierre@0 1610