annotate ad.module @ 1:948362c2a207 ad

update advertisement
author pierre
date Thu, 02 Apr 2009 15:28:21 +0000
parents d8a3998dac8e
children e5584a19768b
rev   line source
pierre@0 1 <?php
pierre@1 2 // $Id: ad.module,v 1.2.2.29.2.83.2.16.2.12 2009/03/31 04:41:03 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 }
pierre@0 160 $src = 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 }
pierre@0 845 }
pierre@0 846
pierre@0 847 /**
pierre@0 848 * Implementation of hook_nodeapi().
pierre@0 849 */
pierre@0 850 function ad_nodeapi(&$node, $op, $teaser, $page) {
pierre@0 851 global $user;
pierre@0 852
pierre@0 853 switch ($op) {
pierre@0 854
pierre@0 855 case 'load':
pierre@0 856 $ad = db_fetch_array(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid));
pierre@0 857 $merge = array_merge((array)$node, (array)$ad);
pierre@0 858 $adtype = module_invoke('ad_'. $ad['adtype'], 'adapi', 'load', $merge);
pierre@0 859 if (is_array($adtype)) {
pierre@0 860 return array_merge($ad, $adtype);
pierre@0 861 }
pierre@0 862 else {
pierre@0 863 return $ad;
pierre@0 864 }
pierre@0 865 break;
pierre@0 866
pierre@0 867 case 'insert':
pierre@0 868 if (isset($node->adtype)) {
pierre@0 869 if ($node->status != 1 && $node->adstatus == 'active') {
pierre@1 870 $node->adstatus = 'expired';
pierre@0 871 }
pierre@0 872 $activated = $node->adstatus == 'active' ? time() : 0;
pierre@1 873 if (!isset($node->autoactivate)) {
pierre@0 874 $node->autoactivate = 0;
pierre@0 875 }
pierre@0 876 if (!isset($node->maxviews)) {
pierre@0 877 $node->maxviews = 0;
pierre@0 878 }
pierre@0 879 if (!isset($node->maxclicks)) {
pierre@0 880 $node->maxclicks = 0;
pierre@0 881 }
pierre@0 882 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 883 ad_statistics_increment($node->nid, 'create');
pierre@0 884 }
pierre@0 885 break;
pierre@0 886
pierre@0 887 case 'update':
pierre@0 888 if (isset($node->adtype)) {
pierre@0 889 $ad = db_fetch_object(db_query('SELECT * FROM {ads} WHERE aid = %d', $node->nid));
pierre@0 890 // Ad must be in approved state to be able to autoactivate it.
pierre@1 891 if ($node->adstatus != 'approved' && isset($node->autoactive) && $node->autoactivate) {
pierre@0 892 if ($node->adstatus == 'active') {
pierre@0 893 // This ad is already active, no need to autoactivate it.
pierre@0 894 $node->autoactivate = 0;
pierre@0 895 }
pierre@0 896 else {
pierre@0 897 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 898 }
pierre@0 899 }
pierre@0 900 // If this node has been upublished, the ad should no longer be active.
pierre@0 901 if ($node->status != 1 && $node->adstatus == 'active') {
pierre@1 902 $node->adstatus = 'expired';
pierre@0 903 }
pierre@0 904 // Check if ad is being manually activated.
pierre@0 905 if ($ad->adstatus != 'active' && $node->adstatus == 'active') {
pierre@0 906 $activated = time();
pierre@0 907 }
pierre@0 908 // Check if ad is being manually expired.
pierre@0 909 else if ($ad->adstatus != 'expired' && $node->adstatus == 'expired') {
pierre@0 910 // Ad has been manually expired.
pierre@1 911 $activated = $ad->activated;
pierre@0 912 $expired = time();
pierre@0 913 }
pierre@0 914 // Ad has not been manually activated or expired, preserve timestamps.
pierre@0 915 else {
pierre@0 916 $activated = $ad->activated;
pierre@0 917 $expired = $ad->expired;
pierre@0 918 }
pierre@0 919 // Ad status has changed, record the event.
pierre@0 920 if ($ad->adstatus != $node->adstatus) {
pierre@0 921 ad_statistics_increment($node->nid, $node->adstatus);
pierre@0 922 }
pierre@0 923 // Update ads table with new information.
pierre@1 924 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 925 ad_statistics_increment($node->nid, 'update');
pierre@0 926 }
pierre@0 927 break;
pierre@0 928
pierre@0 929 case 'delete':
pierre@0 930 db_query("DELETE FROM {ads} WHERE aid = %d", $node->nid);
pierre@0 931 db_query("DELETE FROM {ad_statistics} WHERE aid = %d", $node->nid);
pierre@0 932 // All that's left of the ad is a single timestamp as to when it was
pierre@0 933 // deleted.
pierre@0 934 ad_statistics_increment($node->nid, 'delete');
pierre@0 935 break;
pierre@0 936
pierre@0 937 case 'view':
pierre@0 938 if (isset($node->adtype)) {
pierre@0 939 $node = node_prepare($node, $teaser);
pierre@0 940 $node->content['body'] = array(
pierre@0 941 '#value' => $teaser ? $node->teaser : theme('node_ad', $node, $page),
pierre@0 942 '#weight' => 1,
pierre@0 943 );
pierre@0 944 }
pierre@0 945 break;
pierre@0 946 }
pierre@0 947 // Allow ad type module to act on nodeapi events. The adapi hook provides
pierre@0 948 // access to additional variables not available in the nodeapi hook.
pierre@0 949 if (isset($node->adtype)) {
pierre@0 950 // Don't use module_invoke, as in pre-PHP5 the changes to $node won't be
pierre@0 951 // passed back.
pierre@0 952 $function = "ad_$node->adtype" .'_adapi';
pierre@0 953 if (function_exists($function)) {
pierre@0 954 $function($op, $node);
pierre@0 955 }
pierre@0 956 }
pierre@0 957 // Allow ad cache module to act on nodeapi events.
pierre@0 958 $cache = variable_get('ad_cache', 'none');
pierre@0 959 if ($cache != 'none') {
pierre@0 960 $function = "ad_cache_$cache" .'_adcacheapi';
pierre@0 961 if (function_exists($function)) {
pierre@0 962 $function($op, $node);
pierre@0 963 }
pierre@0 964 }
pierre@1 965
pierre@1 966 // Rebuild the cache after all hooks are invoked.
pierre@1 967 switch ($op) {
pierre@1 968 case 'insert':
pierre@1 969 case 'update':
pierre@1 970 case 'delete':
pierre@1 971 if (variable_get('ad_cache_file_rebuild_realtime', 0) &&
pierre@1 972 isset($node->adtype)) {
pierre@1 973 ad_rebuild_cache();
pierre@1 974 }
pierre@1 975 }
pierre@0 976 }
pierre@0 977
pierre@0 978 function ad_adapi($op, $node = NULL) {
pierre@0 979 switch ($op) {
pierre@0 980 case 'permissions':
pierre@1 981 return array(
pierre@1 982 'access statistics' => TRUE,
pierre@1 983 'access click history' => TRUE,
pierre@1 984 'set status as pending' => FALSE,
pierre@1 985 'set status as denied' => FALSE,
pierre@1 986 'set status from pending to approved' => FALSE,
pierre@1 987 'set status from pending to denied' => FALSE,
pierre@1 988 'set status from approved to active' => TRUE,
pierre@1 989 'set status from approved to offline' => TRUE,
pierre@1 990 'set status from active to offline' => TRUE,
pierre@1 991 'set status from active to expired' => FALSE,
pierre@1 992 'set status from offline to active' => TRUE,
pierre@1 993 'set status from offline to expired' => FALSE,
pierre@1 994 );
pierre@0 995 break;
pierre@0 996 }
pierre@0 997 }
pierre@0 998
pierre@0 999 /**
pierre@0 1000 * Implementation of hook_menu().
pierre@0 1001 */
pierre@0 1002 function ad_menu() {
pierre@0 1003 $items = array();
pierre@0 1004
pierre@0 1005 $items['admin/content/ad'] = array(
pierre@0 1006 'title' => 'Ads',
pierre@0 1007 'page callback' => 'ad_admin_list',
pierre@0 1008 'access arguments' => array('administer advertisements'),
pierre@0 1009 'description' => 'Configure and manage your advertising system.',
pierre@0 1010 'file' => 'ad.admin.inc',
pierre@0 1011 );
pierre@0 1012 $items['admin/content/ad/list'] = array(
pierre@0 1013 'title' => 'List',
pierre@0 1014 'page callback' => 'ad_admin_list',
pierre@0 1015 'access arguments' => array('administer advertisements'),
pierre@0 1016 'type' => MENU_DEFAULT_LOCAL_TASK,
pierre@0 1017 'file' => 'ad.admin.inc',
pierre@0 1018 );
pierre@0 1019 $items['admin/content/ad/configure'] = array(
pierre@0 1020 'title' => 'Settings',
pierre@0 1021 'page callback' => 'drupal_get_form',
pierre@0 1022 'page arguments' => array('ad_admin_configure_settings'),
pierre@0 1023 'access arguments' => array('administer advertisements'),
pierre@0 1024 'type' => MENU_LOCAL_TASK,
pierre@0 1025 'weight' => 3,
pierre@0 1026 'file' => 'ad.admin.inc',
pierre@0 1027 );
pierre@1 1028 $items['node/add/ad/ahah'] = array(
pierre@1 1029 'access arguments' => array('create advertisements'),
pierre@1 1030 'page callback' => 'ad_form_ahah',
pierre@1 1031 'type' => MENU_CALLBACK,
pierre@1 1032 );
pierre@0 1033
pierre@0 1034 ad_menu_add_global_settings($items);
pierre@0 1035
pierre@0 1036 $items['admin/content/ad/groups'] = array(
pierre@0 1037 'title' => 'Ad groups',
pierre@0 1038 'page callback' => 'ad_admin_groups_list',
pierre@0 1039 'access arguments' => array('administer advertisements'),
pierre@0 1040 'type' => MENU_LOCAL_TASK,
pierre@0 1041 'weight' => 5,
pierre@0 1042 'file' => 'ad.admin.inc',
pierre@0 1043 );
pierre@0 1044 $items['admin/content/ad/groups/list'] = array(
pierre@0 1045 'title' => 'List',
pierre@0 1046 'page callback' => 'ad_admin_groups_list',
pierre@0 1047 'access arguments' => array('administer advertisements'),
pierre@0 1048 'type' => MENU_DEFAULT_LOCAL_TASK,
pierre@0 1049 'weight' => 0,
pierre@0 1050 'file' => 'ad.admin.inc',
pierre@0 1051 );
pierre@0 1052 $items['admin/content/ad/groups/add'] = array(
pierre@0 1053 'title' => 'Create group',
pierre@0 1054 'page callback' => 'drupal_get_form',
pierre@0 1055 'page arguments' => array('ad_admin_group_form'),
pierre@0 1056 'access arguments' => array('administer advertisements'),
pierre@0 1057 'type' => MENU_LOCAL_TASK,
pierre@0 1058 'weight' => 3,
pierre@0 1059 'file' => 'ad.admin.inc',
pierre@0 1060 );
pierre@0 1061 $items["admin/content/ad/groups/%ad_group/edit"] = array(
pierre@0 1062 'title' => 'Edit group',
pierre@0 1063 'page callback' => 'drupal_get_form',
pierre@0 1064 'page arguments' => array('ad_admin_group_form', 4),
pierre@0 1065 'access arguments' => array('administer advertisements'),
pierre@0 1066 'weight' => 1,
pierre@0 1067 'file' => 'ad.admin.inc',
pierre@0 1068 );
pierre@0 1069 $items["admin/content/ad/groups/%ad_group/delete"] = array(
pierre@0 1070 'title' => 'Delete group',
pierre@0 1071 'page callback' => 'drupal_get_form',
pierre@0 1072 'page arguments' => array('ad_confirm_group_delete', 4),
pierre@0 1073 'access arguments' => array('administer advertisements'),
pierre@0 1074 'weight' => 2,
pierre@0 1075 'file' => 'ad.admin.inc',
pierre@0 1076 );
pierre@0 1077 $items['admin/content/ad/configure/global'] = array(
pierre@0 1078 'title' => 'Global settings',
pierre@0 1079 'page callback' => 'drupal_get_form',
pierre@0 1080 'page arguments' => array('ad_admin_configure_settings'),
pierre@0 1081 'access arguments' => array('administer advertisements'),
pierre@0 1082 'type' => MENU_DEFAULT_LOCAL_TASK,
pierre@0 1083 'weight' => 0,
pierre@0 1084 'file' => 'ad.admin.inc',
pierre@0 1085 );
pierre@0 1086 $items["node/%node/details/%"] = array(
pierre@0 1087 'title' => 'Click details',
pierre@0 1088 'page callback' => 'ad_click_details',
pierre@0 1089 'page arguments' => array(1, 3),
pierre@0 1090 'access arguments' => array(1, 'access click history'),
pierre@1 1091 'access callback' => 'ad_permission',
pierre@0 1092 'type' => MENU_CALLBACK,
pierre@0 1093 'file' => 'ad.pages.inc',
pierre@0 1094 );
pierre@1 1095 $items["ad/redirect/%"] = array(
pierre@0 1096 'access arguments' => array('show advertisements'),
pierre@0 1097 'type' => MENU_CALLBACK,
pierre@0 1098 'page callback' => 'ad_redirect',
pierre@1 1099 'page arguments' => (array(2)),
pierre@0 1100 );
pierre@0 1101
pierre@0 1102 return $items;
pierre@0 1103 }
pierre@0 1104
pierre@0 1105 /**
pierre@0 1106 * Load settings for all ad modules. Those modules, who don't
pierre@0 1107 * have their settings form, will get a standard one.
pierre@0 1108 */
pierre@0 1109 function ad_menu_add_global_settings(&$menu_items) {
pierre@0 1110 $adtypes = ad_get_types();
pierre@0 1111 foreach ($adtypes as $type => $name) {
pierre@0 1112 // Ad type global settings.
pierre@0 1113 $settings = 'ad_'. $type .'_global_settings';
pierre@1 1114 $file = 'ad_image.module';
pierre@0 1115 if (!function_exists($settings)) {
pierre@0 1116 $settings = 'ad_no_global_settings';
pierre@1 1117 $file = 'ad.admin.inc';
pierre@0 1118 }
pierre@0 1119 $menu_items['admin/content/ad/configure/'. $type] = array(
pierre@0 1120 'title' => $name,
pierre@0 1121 'page callback' => 'drupal_get_form',
pierre@0 1122 'page arguments' => array($settings),
pierre@0 1123 'access arguments' => array('administer advertisements'),
pierre@0 1124 'type' => MENU_LOCAL_TASK,
pierre@0 1125 'weight' => 2,
pierre@0 1126 'file' => 'ad.admin.inc',
pierre@0 1127 );
pierre@0 1128 }
pierre@0 1129 }
pierre@0 1130
pierre@0 1131 /**
pierre@0 1132 * Drupal menu wildcard Ad group loader
pierre@0 1133 */
pierre@0 1134 function ad_group_load($tid) {
pierre@0 1135 if (!is_numeric($tid)) {
pierre@0 1136 return FALSE;
pierre@0 1137 }
pierre@0 1138 $group = ad_groups_list(TRUE, $tid);
pierre@0 1139 if (!isset($group)) {
pierre@0 1140 return FALSE;
pierre@0 1141 }
pierre@0 1142 return $group;
pierre@0 1143 }
pierre@0 1144
pierre@0 1145 /**
pierre@0 1146 * Implementation of hook_block().
pierre@0 1147 */
pierre@0 1148 function ad_block($op = 'list', $delta = 0, $edit = array()) {
pierre@0 1149 switch ($op) {
pierre@0 1150 case 'list':
pierre@0 1151 $blocks = array();
pierre@0 1152 $groups = ad_groups_list();
pierre@0 1153 foreach ($groups as $tid => $name) {
pierre@0 1154 $blocks[$tid]['info'] = t('ad group: @name', array('@name' => $name));
pierre@0 1155 }
pierre@0 1156 return $blocks;
pierre@0 1157 case 'configure':
pierre@0 1158 $form['ad_block_quantity_'. $delta] = array(
pierre@0 1159 '#type' => 'select',
pierre@0 1160 '#title' => t('Number of ads'),
pierre@0 1161 '#default_value' => variable_get('ad_block_quantity_'. $delta, 1),
pierre@0 1162 '#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 1163 '#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 1164 );
pierre@0 1165 return $form;
pierre@0 1166 case 'save':
pierre@0 1167 variable_set('ad_block_quantity_'. $delta, $edit['ad_block_quantity_'. $delta]);
pierre@0 1168 break;
pierre@0 1169 case 'view':
pierre@0 1170 $groups = ad_groups_list();
pierre@0 1171 $block['content'] = ad($delta, variable_get('ad_block_quantity_'. $delta, 1));
pierre@0 1172 return $block;
pierre@0 1173 }
pierre@0 1174 }
pierre@0 1175
pierre@0 1176 /**
pierre@0 1177 * Determine whether the user has a given privilege.
pierre@0 1178 *
pierre@1 1179 * @param $aid
pierre@1 1180 * ID of advertisement.
pierre@0 1181 * @param $permission
pierre@1 1182 * Permission string which should be checked (such as 'access click history')
pierre@0 1183 * @param $account
pierre@0 1184 * User object, which are accessing the ad or current user by default.
pierre@0 1185 */
pierre@1 1186 function ad_permission($aid, $string, $account = NULL) {
pierre@0 1187 global $user;
pierre@1 1188 $access = FALSE;
pierre@0 1189
pierre@1 1190 // by default, check permission for current user
pierre@0 1191 if (!isset($account)) {
pierre@0 1192 $account = $user;
pierre@0 1193 }
pierre@0 1194
pierre@1 1195 // user #1 has all privileges
pierre@0 1196 if ($account->uid == 1) {
pierre@0 1197 return TRUE;
pierre@0 1198 }
pierre@0 1199
pierre@1 1200 // if you have administer permissions, you have all permissions
pierre@0 1201 if (user_access('administer advertisements', $account)) {
pierre@0 1202 return TRUE;
pierre@0 1203 }
pierre@0 1204
pierre@1 1205 // when used in the Drupal menu, $aid may be the full ad object.
pierre@1 1206 if (is_object($aid) && isset($aid->aid)) {
pierre@1 1207 $aid = $aid->aid;
pierre@1 1208 }
pierre@1 1209 else if (is_object($aid)) {
pierre@1 1210 watchdog('ad', 'Invalid aid object passed into ad_permission, no aid->aid set.');
pierre@1 1211 $aid = 0;
pierre@0 1212 }
pierre@0 1213
pierre@1 1214 // invoke ad_owners module to determine user's access
pierre@1 1215 if (module_exists('ad_owners') &&
pierre@1 1216 function_exists('ad_owners_permission')) {
pierre@1 1217 $access = ad_owners_permission($aid, $string, $account);
pierre@1 1218 }
pierre@1 1219 // no ad_owners module, allow acces to statistics and click history
pierre@1 1220 else if (in_array($string, array('access statistics', 'access click history'))) {
pierre@1 1221 $access = TRUE;
pierre@1 1222 }
pierre@1 1223 // with no ad_owners module, all other permissions are denied unless user
pierre@1 1224 // has 'administer advertisements' permission
pierre@1 1225 return $access;
pierre@0 1226 }
pierre@0 1227
pierre@0 1228 /**
pierre@0 1229 * Returns ad types data.
pierre@0 1230 *
pierre@0 1231 * @param $op
pierre@0 1232 * If set to 'name', will only return array of type names ($type => $name).
pierre@0 1233 * If set to 'data', will return all of the type's data
pierre@0 1234 * @param $type
pierre@0 1235 * If not specified, will return array of all available types, else will
pierre@0 1236 * return specific type's name or data.
pierre@0 1237 */
pierre@0 1238 function ad_get_types($op = 'name', $type = NULL) {
pierre@0 1239 $adtypes = module_invoke_all('adapi', 'type', array());
pierre@0 1240 switch ($op) {
pierre@0 1241 case 'name':
pierre@0 1242 if (isset($type)) {
pierre@0 1243 return $adtypes[$type]['name'];
pierre@0 1244 }
pierre@0 1245 else {
pierre@0 1246 foreach ($adtypes as $type => $data) {
pierre@0 1247 $adtypes[$type] = $data['name'];
pierre@0 1248 }
pierre@0 1249 return $adtypes;
pierre@0 1250 }
pierre@0 1251 case 'data':
pierre@0 1252 if (isset($type)) {
pierre@0 1253 return $adtypes[$type];
pierre@0 1254 }
pierre@0 1255 else {
pierre@0 1256 return $adtypes;
pierre@0 1257 }
pierre@0 1258 }
pierre@0 1259 }
pierre@0 1260
pierre@0 1261 /**
pierre@0 1262 * Return an array of all groups, or a specific group.
pierre@0 1263 *
pierre@0 1264 * @param $object
pierre@0 1265 * If FALSE, will return only name of group(s). If TRUE, will return full
pierre@0 1266 * group object including ->name, ->description, and ->tid.
pierre@0 1267 * @param $tid
pierre@0 1268 * If set to an integer >0, will only return group info about that specific
pierre@0 1269 * group.
pierre@0 1270 */
pierre@0 1271 function ad_groups_list($object = FALSE, $tid = NULL) {
pierre@0 1272 static $groups = array();
pierre@0 1273 static $names = array();
pierre@0 1274
pierre@0 1275 // Return the full group object(s).
pierre@0 1276 if ($object) {
pierre@0 1277 if (empty($groups)) {
pierre@0 1278 $tids = taxonomy_get_tree(_ad_get_vid());
pierre@0 1279 if (is_array($tids)) {
pierre@0 1280 foreach ($tids as $group) {
pierre@0 1281 $groups[$group->tid]->name = $group->name;
pierre@0 1282 $groups[$group->tid]->description = $group->description;
pierre@0 1283 $groups[$group->tid]->tid = $group->tid;
pierre@0 1284 $groups[$group->tid]->weight = $group->weight;
pierre@0 1285 }
pierre@0 1286 }
pierre@0 1287 // Hard coded "default" group with tid of 0.
pierre@0 1288 $groups[0]->name = t('default');
pierre@0 1289 $groups[0]->description = t('The default ad group is comprised of all ads not assigned to any other ad group.');
pierre@0 1290 $groups[0]->tid = 0;
pierre@0 1291 $groups[0]->weight = 0;
pierre@0 1292 }
pierre@0 1293 // Return a specific group object.
pierre@0 1294 if ((int)$tid) {
pierre@0 1295 return $groups[$tid];
pierre@0 1296 }
pierre@0 1297 // Return an array of all group objects.
pierre@0 1298 else {
pierre@0 1299 return $groups;
pierre@0 1300 }
pierre@0 1301 }
pierre@0 1302 // Return only the group name(s).
pierre@0 1303 else {
pierre@0 1304 if (empty($names)) {
pierre@0 1305 $tids = taxonomy_get_tree(_ad_get_vid());
pierre@0 1306 if (is_array($tids)) {
pierre@0 1307 foreach ($tids as $group) {
pierre@0 1308 $names[$group->tid] = $group->name;
pierre@0 1309 }
pierre@0 1310 }
pierre@0 1311 // Hard coded "default" group with tid of 0.
pierre@0 1312 $names[0] = t('default');
pierre@0 1313 }
pierre@0 1314 // Return a specific group name.
pierre@0 1315 if ((int)$tid) {
pierre@0 1316 return $names[$tid];
pierre@0 1317 }
pierre@0 1318 // Return an array of all group names.
pierre@0 1319 else {
pierre@0 1320 return $names;
pierre@0 1321 }
pierre@0 1322 }
pierre@0 1323 }
pierre@0 1324
pierre@0 1325 /**
pierre@0 1326 * Implement ad notify api _hook.
pierre@0 1327 */
pierre@0 1328 function ad_adnotifyapi($op, $arg1 = NULL, $arg2 = NULL) {
pierre@0 1329 switch ($op) {
pierre@0 1330 // Make the following events available for notification.
pierre@0 1331 case 'register':
pierre@0 1332 return array(
pierre@0 1333 '-expired' => t('Email @when before the advertisement will expire.'),
pierre@0 1334 'expired' => t('Email @when after the advertisement is expired.'),
pierre@0 1335 '-active' => t('Email @when before the advertisement will be activated (if scheduled).'),
pierre@0 1336 'active' => t('Email @when after the advertisement is activated.'),
pierre@0 1337 'click' => t('Email @when after the advertisement is clicked.'),
pierre@0 1338 'approved' => t('Email @when after the advertisement is approved.'),
pierre@0 1339 'denied' => t('Email @when after the advertisement is denied.'),
pierre@0 1340 );
pierre@0 1341 break;
pierre@0 1342 case '-expired':
pierre@0 1343 $node = node_load($arg1->aid);
pierre@0 1344 if (isset($node->autoexpire) && $node->autoexpire) {
pierre@0 1345 if ((time() + $arg1->delay >= $node->autoexpire) &&
pierre@0 1346 ($arg1->sent + $arg1->delay < $node->autoexpire)) {
pierre@0 1347 return array('-expired' => 1);
pierre@0 1348 }
pierre@0 1349 }
pierre@0 1350 break;
pierre@0 1351 case '-active':
pierre@0 1352 $node = node_load($arg1->aid);
pierre@0 1353 if (isset($node->autoactivate) && $node->autoactivate) {
pierre@0 1354 if ((time() + $arg1->delay >= $node->autoactivate) &&
pierre@0 1355 ($arg1->sent + $arg1->delay < $node->autoactivate)) {
pierre@0 1356 return array('-active' => 1);
pierre@0 1357 }
pierre@0 1358 }
pierre@0 1359 break;
pierre@0 1360 case 'mail_text':
pierre@0 1361 switch ($arg1) {
pierre@0 1362 case 'expired':
pierre@0 1363 return array(
pierre@1 1364 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1365 '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 1366 );
pierre@0 1367 case '-expired':
pierre@0 1368 return array(
pierre@1 1369 'subject' => t('[%site-name ad] expiration notification'),
pierre@1 1370 '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 1371 );
pierre@0 1372 case 'active':
pierre@0 1373 return array(
pierre@1 1374 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1375 '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 1376 );
pierre@0 1377 case '-active':
pierre@0 1378 return array(
pierre@1 1379 'subject' => t('[%site-name ad] activation notification'),
pierre@1 1380 '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 1381 );
pierre@0 1382 case 'click':
pierre@0 1383 return array(
pierre@1 1384 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1385 '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 1386 );
pierre@0 1387 case 'approved':
pierre@0 1388 return array(
pierre@1 1389 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1390 '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 1391 );
pierre@0 1392 case 'denied':
pierre@0 1393 return array(
pierre@1 1394 'subject' => t('[%site-name ad] %event notification'),
pierre@1 1395 '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 1396 );
pierre@0 1397 }
pierre@0 1398 break;
pierre@0 1399 }
pierre@0 1400 }
pierre@0 1401
pierre@0 1402 function _ad_check_installation() {
pierre@0 1403 // Verify serve.php exists and is readable.
pierre@0 1404 $adserve = variable_get('adserve', '');
pierre@0 1405 $adserveinc = variable_get('adserveinc', '');
pierre@0 1406 if (!file_exists($adserve)) {
pierre@0 1407 // The serve.php file should be in the same directory as the ad.module.
pierre@0 1408 $adserve = drupal_get_path('module', 'ad') .'/serve.php';
pierre@0 1409 variable_set('adserve', $adserve);
pierre@0 1410 }
pierre@0 1411 if (!is_readable($adserve)) {
pierre@0 1412 variable_set('adserve', '');
pierre@0 1413 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 1414 }
pierre@0 1415 if (!file_exists($adserveinc)) {
pierre@0 1416 // The adserve.inc file should be in the same directory as the ad.module.
pierre@0 1417 $adserveinc = drupal_get_path('module', 'ad') .'/adserve.inc';
pierre@0 1418 variable_set('adserveinc', $adserveinc);
pierre@0 1419 }
pierre@0 1420 if (!is_readable($adserveinc)) {
pierre@0 1421 variable_set('adserveinc', '');
pierre@0 1422 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 1423 }
pierre@0 1424
pierre@0 1425 // Validate vid in vocabulary table.
pierre@0 1426 $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = 'ad'"));
pierre@0 1427 if ($vid != variable_get('ad_group_vid', '')) {
pierre@0 1428 drupal_set_message(t('Invalid vocabulary defined for advertisements, attempting to auto-fix.'), 'error');
pierre@0 1429 if ($vid) {
pierre@0 1430 db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid', ''));
pierre@0 1431 variable_set('ad_group_vid_restore', variable_get('ad_group_vid', ''));
pierre@0 1432 }
pierre@0 1433 variable_del('ad_group_vid');
pierre@0 1434 }
pierre@0 1435 else {
pierre@0 1436 // Validate vid in vocabulary_node_types table.
pierre@0 1437 $result = db_query("SELECT vid FROM {vocabulary_node_types} WHERE type = 'ad'");
pierre@0 1438 $found = FALSE;
pierre@0 1439 while ($vocab = db_fetch_object($result)) {
pierre@0 1440 if ($vocab->vid == variable_get('ad_group_vid', '')) {
pierre@0 1441 $found = TRUE;
pierre@0 1442 }
pierre@0 1443 }
pierre@0 1444 if (!$found) {
pierre@0 1445 drupal_set_message(t('Missing vocabulary node type for advertisements, attempting to auto-fix.'), 'error');
pierre@0 1446 db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d OR type = 'ad'", variable_get('ad_group_vid', ''));
pierre@0 1447 db_query("DELETE FROM {vocabulary} WHERE vid = %d", variable_get('ad_group_vid', ''));
pierre@0 1448 variable_set('ad_group_vid_restore', variable_get('ad_group_vid', ''));
pierre@0 1449 variable_del('ad_group_vid');
pierre@0 1450 }
pierre@0 1451 }
pierre@0 1452
pierre@0 1453 _ad_get_vid();
pierre@0 1454 // Preserve old ad groups, if any.
pierre@0 1455 if (($old = variable_get('ad_group_vid_restore', '')) &&
pierre@0 1456 $vid = variable_get('ad_group_vid', '')) {
pierre@0 1457 drupal_set_message(t('Restoring orphaned ad group configuration.'));
pierre@0 1458 db_query('UPDATE {term_data} SET vid = %d WHERE vid = %d', $vid, $old);
pierre@0 1459 variable_set('ad_group_vid_restore', '');
pierre@0 1460 }
pierre@0 1461
pierre@0 1462 $rid = db_result(db_query_range("SELECT rid FROM {permission} WHERE perm LIKE '%%show advertisements%%'", 1));
pierre@0 1463 if (!$rid) {
pierre@0 1464 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 1465 }
pierre@0 1466
pierre@0 1467 // Allow modules to define an action to take each time an ad is served.
pierre@0 1468 // When modules define 'adserve_select' or 'adserve_filter', they must set
pierre@0 1469 // the 'function' and 'path' parameters. The 'weight' parameter can
pierre@0 1470 // optionally be set.
pierre@0 1471 // function: the function to call when serving an add
pierre@0 1472 // path: the path to the include file where $function is defined
pierre@0 1473 // Modules can define actions that happen when advertisements are served.
pierre@0 1474 // Currently support actions are:
pierre@0 1475 // - init_text (display content before displaying ads) // TODO
pierre@0 1476 // - select (alter which ads are selected to be displayed) // TODO
pierre@0 1477 // - filter (filter selected ads before they are displayed) // TODO
pierre@0 1478 // - exit_text (display content after displaying ads) // TODO
pierre@0 1479 $hooks = array('init_text', 'select', 'filter', 'exit_text');
pierre@0 1480 foreach ($hooks as $hook) {
pierre@0 1481 $adserve_actions = module_invoke_all('adapi', "adserve_$hook", array());
pierre@0 1482 $actions = array();
pierre@0 1483 foreach ($adserve_actions as $name => $action) {
pierre@0 1484 if (is_numeric($action['weight'])) {
pierre@0 1485 $weight = $action['weight'];
pierre@0 1486 }
pierre@0 1487 else {
pierre@0 1488 // weight is an optional, defaults to 0
pierre@0 1489 $weight = $action['weight'] = 0;
pierre@0 1490 }
pierre@0 1491 $actions[$weight .'.'. $name] = $action;
pierre@0 1492 $actions[$weight .'.'. $name]['name'] = $name;
pierre@0 1493 }
pierre@0 1494 // order actions by weight (multiple same-weight actions sorted by alpha)
pierre@0 1495 ksort($actions);
pierre@0 1496 variable_set("adserve_$hook", serialize($actions));
pierre@0 1497 }
pierre@0 1498
pierre@0 1499 module_invoke_all('adapi', 'check_install', array());
pierre@0 1500 }
pierre@0 1501
pierre@0 1502 /**
pierre@0 1503 * Creates a vocabulary for use by ad groups if not already created.
pierre@0 1504 */
pierre@0 1505 function _ad_get_vid() {
pierre@0 1506 $vid = variable_get('ad_group_vid', '');
pierre@0 1507 if (empty($vid)) {
pierre@0 1508 // No vid stored in the variables table, check if one even exists.
pierre@0 1509 $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE module = '%s'", 'ad'));
pierre@0 1510 if (!$vid) {
pierre@0 1511 // No vid, so we create one.
pierre@0 1512 $edit = array(
pierre@0 1513 'name' => t('Ad groups'),
pierre@0 1514 'multiple' => 1,
pierre@0 1515 'required' => 0,
pierre@0 1516 'hierarchy' => 0,
pierre@0 1517 'relations' => 0,
pierre@0 1518 'module' => 'ad',
pierre@0 1519 'nodes' => array('ad' => 1)
pierre@0 1520 );
pierre@0 1521
pierre@0 1522 taxonomy_save_vocabulary($edit);
pierre@0 1523 $vid = $edit['vid'];
pierre@0 1524 }
pierre@0 1525 // Save the vid for next time.
pierre@0 1526 variable_set('ad_group_vid', $vid);
pierre@0 1527 }
pierre@0 1528 return $vid;
pierre@0 1529 }
pierre@0 1530
pierre@0 1531 /**
pierre@0 1532 * Builds the necessary HTML to display an image-based impressions counter.
pierre@0 1533 */
pierre@0 1534 function ad_display_image($ad, $css = TRUE) {
pierre@0 1535 global $base_url;
pierre@0 1536 $adserve = variable_get('adserve', '');
pierre@0 1537 $cache = variable_get('ad_cache', 'none');
pierre@0 1538 $variables = "?o=image";
pierre@0 1539 if (is_object($ad)) {
pierre@0 1540 $aid = $ad->aid;
pierre@0 1541 }
pierre@0 1542 else {
pierre@0 1543 /**
pierre@0 1544 * No ad is specified, so we're just tracking traffic.
pierre@0 1545 */
pierre@0 1546 $aid = 0;
pierre@0 1547 }
pierre@0 1548 $variables .= "&amp;a=$aid";
pierre@0 1549 if ($cache != 'none') {
pierre@0 1550 $variables .= '&amp;c='. $cache . module_invoke('ad_cache_'. $cache, 'adcacheapi', 'display_variables', array());
pierre@0 1551 }
pierre@0 1552 $output = '<img src="'. url($base_url .'/'. $adserve . $variables) .'" height="0" width="0" alt="view counter" />';
pierre@0 1553 if ($css) {
pierre@0 1554 return '<div class="ad-image-counter">'. $output .'</div>';
pierre@0 1555 }
pierre@0 1556 else {
pierre@0 1557 return $output;
pierre@0 1558 }
pierre@0 1559 }
pierre@0 1560
pierre@0 1561 /**
pierre@0 1562 * Retrieve the group name from the nid.
pierre@0 1563 */
pierre@0 1564 function _ad_get_group($nid) {
pierre@0 1565 static $groups = array();
pierre@0 1566
pierre@0 1567 if (!isset($groups[$nid])) {
pierre@0 1568 $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 1569 while ($term = db_fetch_object($result)) {
pierre@0 1570 $terms[] = $term->name;
pierre@0 1571 }
pierre@0 1572 if (!empty($terms)) {
pierre@0 1573 $groups[$nid] = implode(', ', $terms);
pierre@0 1574 }
pierre@0 1575 else {
pierre@0 1576 $groups[$nid] = t('default');
pierre@0 1577 }
pierre@0 1578 }
pierre@0 1579
pierre@0 1580 return $groups[$nid];
pierre@0 1581 }
pierre@0 1582