annotate ad.module @ 8:32c1a7d9e1fa ad tip

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