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