/[drupal]/contributions/modules/syndication/syndication.module
ViewVC logotype

Contents of /contributions/modules/syndication/syndication.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.59 - (show annotations) (download) (as text)
Sun Jan 18 06:01:33 2009 UTC (10 months, 1 week ago) by aaron1234nz
Branch: MAIN
CVS Tags: HEAD
Changes since 1.58: +277 -230 lines
File MIME type: text/x-php
Initial comit for Drupal 6
1 <?php
2 // $Id: syndication.module,v 1.58 2008/06/18 22:43:08 nedjo Exp $
3
4 /**
5 * Implementation of hook_menu().
6 */
7 function syndication_menu() {
8 $items['syndication'] = array(
9 'title' => 'RSS feeds',
10 'access arguments' => array('access content'),
11 'page callback' => 'syndication_page',
12 'weight' => 6
13 );
14 $items['admin/content/syndication'] = array(
15 'title' => 'RSS feed syndication',
16 'access arguments' => array('access administration pages'),
17 'page callback' => 'drupal_get_form',
18 'page arguments' => array('syndication_admin_settings'),
19 );
20 $items['syndication/builder'] = array(
21 'title' => 'RSS feed builder',
22 'access arguments' => array('access content'),
23 'page callback' => 'drupal_get_form',
24 'page arguments' => array('syndication_taxonomy_builder'),
25 );
26 return $items;
27 }
28
29 /**
30 * Implementation of hook_block().
31 */
32 function syndication_block($op = 'list', $delta = 0) {
33 if ($op == 'list') {
34 $blocks[0]['info'] = t('Syndicate (more)');
35 return $blocks;
36 }
37 elseif ($op == 'view') {
38 if (user_access('access content')) {
39 $block['subject'] = t('Syndicate');
40 $pagetype = arg(0);
41 if ($pagetype == 'blog') {
42 $userid = arg(1);
43 $linkurl = is_numeric($userid) ? "blog/$userid/feed" : 'blog/feed';
44 }
45 else {
46 $linkurl = 'rss.xml';
47 }
48 $block['content'] = theme('feed_icon', url($linkurl), t('More'));
49 $block['content'] .= '<div class="more-link">'. l(t('more'), 'syndication', array('title' => t("Review all XML feeds exported by %sn", array("%sn" => variable_get('site_name', 'Drupal'))))) ."</div>\n";
50 return $block;
51 }
52 }
53 }
54
55 /**
56 * Menu callback
57 * Syndication page.
58 */
59 function syndication_page() {
60 drupal_add_css(drupal_get_path('module', 'syndication') .'/syndication.css');
61
62 //atom
63 if (module_exists('atom') && variable_get('syndication_atom', 0)) {
64 $output .= theme('box', t('Atom feed'), l(t('Atom front page feed'), 'atom/feed'));
65 }
66
67 //blogs
68 if (module_exists('blog') && variable_get('syndication_blogs', 0)) {
69 $output .= theme('box', t('Blogs'), syndication_blogs());
70 }
71
72 //aggregator
73 if (module_exists('aggregator') && user_access('access news feeds') && variable_get('syndication_aggregator', 0)) {
74 $output .= theme('box', t('External feeds'), syndication_opml());
75 }
76
77 //taxonomy
78 $syndication_vocab = variable_get('syndication_vocabularies', array());
79 foreach ($syndication_vocab as $key => $value) {
80 // Throw away the vids that aren't enabled.
81 if (!$value) {
82 unset($syndication_vocab[$key]);
83 }
84 }
85 if (module_exists('taxonomy') && user_access('access content') && !empty($syndication_vocab)) {
86 $output .= theme('box', t('Categories'), syndication_vocabularies());
87 }
88
89 //views
90 $syndication_views = variable_get('syndication_views', array());
91 if (module_exists('views') && !empty($syndication_views)) {
92 if ($views = syndication_views_rss()) {
93 $output .= theme('box', t('Views'), $views);
94 }
95 }
96
97 //custom
98 $syndication_custom = variable_get('syndication_custom', array());
99 if (!empty($syndication_custom)) {
100 foreach ($syndication_custom as $name) {
101 $result = module_invoke($name, 'syndication');
102 foreach ($result as $box) {
103 $output .= theme('box', $box['subject'], $box['content']);
104 }
105 }
106 }
107 if (empty($output)) {
108 $output = t('Sorry, there are no feeds available.');
109 }
110
111 return '<div id="syndication-page">'. $output .'</div>';
112 }
113
114 /**
115 * Generate a form for searching for user blogs feeds.
116 * @return $form fragment
117 */
118 function syndication_users() {
119 if (module_exists('atom')) {
120 $prefix = '<p>'. t("At <i>%sn</i>, all users have a <a href='!rss'>RSS</a> and <a href='!atom'>Atom<a> feed for their blog, as well as each individual user.",
121 array('%sn' => variable_get('site_name', 'Drupal'), '!rss' => url('blog/feed'), '!atom' => url('blog/atom/feed'))) .'</p>';
122 }
123 else {
124 $prefix = '<p>'. t("At <i>%sn</i>, <a href='!all'>all users</a> and each user, have an RSS feed for their blog.",
125 array('%sn' => variable_get('site_name', 'Drupal'), '!all' => url('blog/feed'))) .'</p>';
126 }
127 $form['name'] = array(
128 '#type' => 'textfield',
129 '#title' => t('Search users'),
130 '#prefix' => $prefix,
131 '#description' => t('Enter a username to view her blog feed, and other details.'),
132 '#autocomplete_path' => 'user/autocomplete',
133 );
134 $form['submit'] = array('#type' => 'button', '#value' => t('Search'));
135
136 return $form;
137 }
138
139 /**
140 * Generate a list of feeds for personal blogs.
141 */
142 function syndication_blogs() {
143 $result = db_query_range("SELECT DISTINCT(u.uid), u.name FROM {users} u INNER JOIN {node} n ON u.uid = n.uid WHERE n.type = 'blog' AND n.status = 1", 0, 16);
144 while ($account = db_fetch_object($result)) {
145 $author = $account->name .': '. l(t('RSS feed'), "blog/$account->uid/feed");
146 $author .= module_exists('atom') ? ', '. l(t('Atom feed'), "blog/$account->uid/atom/feed") : '';
147 $authors[] = $author;
148 }
149 if ($authors) {
150 $output = theme('item_list', $authors, t('Recent Blog Authors'));
151 }
152
153 $output .= drupal_get_form('syndication_users');
154
155 if ($name = $_POST['name']) {
156 // TODO: This query was already executed in validate hook. If I knew what I was doing, I would not run it again here.
157 $result = db_query("SELECT uid, name FROM {users} WHERE uid > 0 and name LIKE '%s' ORDER BY access DESC", '%'. $name .'%');
158 $i=0;
159 while ($account = db_fetch_object($result)) {
160 $rows[$i][] = theme('username', $account) .':';
161 $rows[$i][] = l(t("RSS feed"), "blog/$account->uid/feed");
162 if (module_exists('atom')) {
163 $rows[$i][] = l(t("Atom feed"), "blog/$account->uid/atom/feed");
164 }
165 $rows[$i][] = l(t("blog"), "blog/$account->uid");
166 $i++;
167 }
168 if ($rows) {
169 $output .= theme('table', array(), $rows);
170 }
171 }
172 $output .= $frm;
173
174 return $output;
175 }
176
177 /**
178 * Follows a similar pattern from og_vocab.module should ideally be in
179 * taxonomy.module.
180 */
181 function syndication_vocabularies() {
182 $syndication_columns = variable_get('syndication_columns', 3);
183 $vocab_number = 0;
184 for($i=0; $i<$syndication_columns; $i++) {
185 $header[] = ' ';
186 }
187 foreach (variable_get('syndication_vocabularies', array()) as $vid) {
188 $vocab = taxonomy_vocabulary_load($vid);
189 $tree = taxonomy_get_tree($vid);
190 $items = syndication_taxonomy_build_list_items($index = 0, $tree);
191 if ($items) {
192 $col_num = $vocab_number % $syndication_columns;
193 $columns[$col_num] .= theme('item_list', $items, $vocab->name);
194 $vocab_number++;
195 }
196 }
197 $output = theme('syndication_columns', $columns);
198 $output .= l('Combine terms into a single feed', 'syndication/builder');
199 return $output;
200 }
201
202 /**
203 * Helper function for syndication_taxonomy.
204 */
205 function syndication_taxonomy_build_list_items(&$index, $tree) {
206 $items = array();
207 $current_depth = $tree[$index]->depth;
208 while ($index < count($tree) && $tree[$index]->depth >= $current_depth) {
209 $term = $tree[$index];
210 $count = taxonomy_term_count_nodes($term->tid);
211 if ($count) {
212 $term_path = "taxonomy/term/$term->tid/0/feed";
213 $term_link = l(t($term->name), $term_path, array('title' => t($term->description)));
214 if ($term->depth) {
215 $prefix = str_repeat('--', $term->depth) .' ';
216 }
217 else {
218 $prefix = "";
219 }
220 $item = $prefix . $term_link ." ($count)";
221 $items[] = $item;
222 $index++;
223 }
224 else {
225 $index++;
226 }
227 }
228 return $items;
229 }
230
231 /**
232 * Menu callback for syndication_taxonomy_builder.
233 */
234 function syndication_taxonomy_builder() {
235 $form['intro'] = array(
236 '#type' => 'markup',
237 '#value' => t('You can subscribe to more than one category in a single RSS feed. Please select the RSS feeds you would like to subscribe to then press the "Generate feed" button.'),
238 );
239 foreach (variable_get('syndication_vocabularies', array()) as $vid) {
240 $vocab = taxonomy_vocabulary_load($vid);
241 $tree = taxonomy_get_tree($vid);
242 $items = syndication_taxonomy_build_list_items($index = 0, $tree);
243 if ($items) {
244 $index = 0;
245 $options = array();
246 $current_depth = $tree[$index]->depth;
247 $form['categories'][$vocab->name] = array(
248 '#type' => 'fieldset',
249 '#title' => $vocab->name,
250 '#collapsible' => TRUE,
251 '#collapsed' => FALSE,
252 );
253 while ($index < count($tree) && $tree[$index]->depth >= $current_depth) {
254 $term = $tree[$index];
255 $count = taxonomy_term_count_nodes($term->tid);
256 if ($count) {
257 $options[$term->tid] = $term->name;
258 $index++;
259 }
260 else {
261 $index++;
262 }
263 }
264 //the vocab name must be urlencoded here because this breaks if there is a space in the vocab name
265 $form['categories'][$vocab->name][urlencode($vocab->name)] = array(
266 '#type' => 'checkboxes',
267 '#options' => $options,
268 '#columns' => variable_get('syndication_columns', 3),
269 '#theme' => 'syndication_taxonomy_builder_columns_checkboxes',
270 );
271 }
272 }
273 $form['submit'] = array(
274 '#type' => 'submit',
275 '#value' => 'Generate feed',
276 );
277 return $form;
278 }
279
280 /**
281 * Implementation of hook_submit
282 */
283 function syndication_taxonomy_builder_submit($form, &$form_state) {
284 foreach ($form_state['values'] as $category) {
285 if (is_array($category) && !empty($category)) {
286 foreach ($category as $vid => $enabled) {
287 if ($enabled >0) {
288 $feed[] = $vid;
289 }
290 }
291 }
292 }
293 if (!empty($feed)) {
294 drupal_goto("taxonomy/term/". implode("+", $feed) ."/0/feed");
295 }
296 }
297
298 /**
299 * Validates user blog feed search form.
300 */
301 function syndication_users_validate($form, &$form_state) {
302 $result = db_query("SELECT uid, name FROM {users} WHERE name LIKE '%%%s%%' AND uid > 0 ORDER BY access DESC",$form_state['values']["name"]);
303 if (db_fetch_object($result)) {
304 $form_state['values']['result'] = $result;
305 }
306 else {
307 form_set_error('name', t('Username not found.'));
308 drupal_goto('syndication');
309 }
310 }
311
312 /**
313 * Generates a link to aggregator.module OPML file.
314 */
315 function syndication_opml() {
316 $output = t('In addition to displaying RSS feeds, <i>%sn</i> offers <a href="!link">this OPML</a> which lists all RSS feeds that are collected here.',
317 array ('%sn' => variable_get('site_name', 'Drupal'), '!link' => url('aggregator/opml')));
318 return $output;
319 }
320
321 /**
322 * Generates a list of feeds from views_rss.module.
323 */
324 function syndication_views_rss() {
325 $vids = variable_get('syndication_views', array());
326 foreach ($vids as $key => $value) {
327 // Throw away the vids that aren't enabled.
328 if (!$value) {
329 unset($vids[$key]);
330 }
331 }
332 // Only bother getting results if at least one vid is enabled.
333 if ($vids) {
334 $result = _syndication_return_views_rss_feeds($vids);
335 foreach ($result as $view_item) {
336 $view = views_get_view($view_item->name);
337 $feed_path = $view->display[$view_item->id]->display_options['path'];
338 $feed_title = $view_item->display_title;
339 $items[] = l($feed_title, $feed_path, array('attributes' => array('class' => 'syndication_view_rss')));
340 }
341 $output = theme('item_list', $items);
342 }
343 return $output;
344 }
345
346 /**
347 * Helper function to get all views that generate rss feeds from the database.
348 * Accepts an array of views ids (vids) to limit the results.
349 *
350 * @param $args
351 * An array of views ids.
352 * @return
353 * Database result object ( containing the vid, name, and display_title) or null if no feeds exist.
354 */
355 function _syndication_return_views_rss_feeds($vids = array()) {
356 if (!empty($vids)) {
357 $limit = implode("', '", $vids);
358 $result = db_query("SELECT vv.vid, vd.id, vd.display_title, vv.name FROM {views_display} vd JOIN {views_view} vv ON vd.vid = vv.vid WHERE vd.display_plugin = 'feed' AND vv.name IN ('%s')", $limit);
359 }
360 else {
361 $result = db_query("SELECT vv.vid, vd.id, vd.display_title, vv.name FROM {views_display} vd JOIN {views_view} vv ON vd.vid = vv.vid WHERE vd.display_plugin = 'feed'");
362 }
363
364 while ($row = db_fetch_object($result)) {
365 $view[] = $row;
366 }
367 return $view;
368 }
369
370 /**
371 * Theme views_rss feeds list.
372 */
373 function theme_syndication_views_rss($rows) {
374 if (is_array($rows)) {
375 $output = theme('item_list', $rows, '', 'ul');
376 }
377 return $output;
378 }
379
380 /**
381 * Syndication module configuration form.
382 */
383 function syndication_admin_settings() {
384 //general
385 $form['syndication_columns'] = array(
386 '#type' => 'textfield',
387 '#title' => t('Columns'),
388 '#default_value' => variable_get('syndication_columns', 3),
389 '#description' => t('The number of columns to use on the display page?'),
390 );
391
392 //blogs
393 if (module_exists('blog')) {
394 $form['syndication_blogs'] = array(
395 '#type' => 'checkbox',
396 '#title' => t('Blogs'),
397 '#default_value' => variable_get('syndication_blogs', 0),
398 '#description' => t('Should be blogs be included on the syndication page?'),
399 );
400 }
401
402 //atom front page feed
403 if (module_exists('atom')) {
404 $form['syndication_atom'] = array(
405 '#type' => 'checkbox',
406 '#title' => t('Atom feed'),
407 '#default_value' => variable_get('syndication_atom', 0),
408 '#description' => t('Should be front page atom feed be included on the syndication page?'),
409 );
410 }
411 //aggregotor front page feed
412 if (module_exists('aggregator')) {
413 $form['syndication_aggregator'] = array(
414 '#type' => 'checkbox',
415 '#title' => t('Atom feed'),
416 '#default_value' => variable_get('syndication_aggregator', 0),
417 '#description' => t('Should be aggregator OPML feed be included on the syndication page?'),
418 );
419 }
420
421 //taxonomy
422 foreach (taxonomy_get_vocabularies() as $vid => $vocab) {
423 $options[$vid] = $vocab->name;
424 }
425 $form['syndication_vocabularies'] = array(
426 '#type' => 'checkboxes',
427 '#title' => t('Vocabularies'),
428 '#options' => $options,
429 '#default_value' => variable_get('syndication_vocabularies', array()),
430 '#description' => t('Select the vocabularies which should appear in the <em>Categories</em> block on the <a href="@syndication">syndication page</a>', array('@syndication' => url('syndication'))),
431 );
432
433 //views
434 if (module_exists('views')) {
435 $options = array();
436 $views = _syndication_return_views_rss_feeds();
437 foreach ($views as $view) {
438 $options[$view->name] = $view->display_title;
439 }
440 $form['syndication_views'] = array(
441 '#type' => 'checkboxes',
442 '#title' => t('Views'),
443 '#options' => $options,
444 '#default_value' => variable_get('syndication_views', array()),
445 '#description' => t('Select the views which should appear in the <em>Views</em> block on the <a href="@syndication">syncidation page</a>', array('@syndication' => url('syndication'))),
446 );
447 }
448
449 //hook_syndication implementations
450 unset($options);
451 foreach (module_list() as $name) {
452 $result = module_invoke($name, 'syndication');
453 if (isset($result)) {
454 foreach ($result as $box) {
455 $options[] = $box['subject'];
456 }
457 }
458 }
459 if (!empty($options)) {
460 $form['syndication_custom'] = array(
461 '#type' => 'checkboxes',
462 '#title' => t('Other'),
463 '#options' => $options,
464 '#default_value' => variable_get('syndication_custom', array()),
465 '#description' => t('Select the other feeds which should appear in the <em>Other</em> block on the <a href="@syndication">syncidation page</a>', array('@syndication' => url('syndication'))),
466 );
467 }
468 return system_settings_form($form);
469 }
470
471 /**
472 * Implementation of hook_help().
473 */
474 function syndication_help($path, $arg) {
475 $output = '';
476 switch ($path) {
477 case 'admin/help#syndication':
478 $output = syndication_help_intro();
479 $output .= syndication_help_api(); //TODO move this to Doxygen
480 break;
481 case 'admin/modules#description':
482 $output .= t("Adds a Syndication block, links to more feeds");
483 break;
484 }
485 return $output;
486 }
487
488 /**
489 * Helper function for syndication_help().
490 * @return Help text
491 */
492 function syndication_help_intro() {
493 $output = '
494 <p>Syndication.module offers a web page which centralizes all of the RSS feeds
495 generated by Drupal. This helps users find interesting feeds from your web site.</p>
496
497 <p>Currently, the syndication page helps visitors find the following feeds.
498 <ul>
499 <li>the blog feed of any user or all users
500 <li>node feeds for any taxonomy terms, including composites of terms (requires <i>taxonomy_dhtml.module</i>)
501 <li>a directory of all feeds being consumed by the <i>import.module</i>
502 </ul>
503 </p>
504
505 <h3>For Module Developers - Syndication hook</h3>';
506
507 return $output;
508 }
509
510 /**
511 * TODO: move this to Doxygen.
512 */
513 function syndication_help_api() {
514
515 $output = '
516
517 Any module can export boxes to the syndication page. You do so
518 by creating a <i>modulename</i>_syndication function which returns
519 an associative array of boxes, much like the block module. Each box
520 in the array requires <i>subject</i> and <i>content</i> fields. Example:
521 <pre>
522 function mymodule_syndication() {
523
524 // Creating the first box
525
526 $box[0]["subject"] = "Existentialism";
527 $box[0]["content"] = "So many feeds in this world";
528
529 // Lets create a one box more
530
531 $box[1]["subject"] = "Got any question?";
532 $box[1]["content"] = "Who, Where, Why, When";
533 return $box;
534 }
535 </pre>';
536
537 return $output;
538 }
539
540 /**
541 * Implementation of hook_theme().
542 */
543 function syndication_theme() {
544 return array(
545 'syndication_taxonomy_builder_columns_checkboxes' => array(
546 'arguments' => array('element' => array()),
547 ),
548 'syndication_columns' => array(
549 'arguments' => array('data' => array()),
550 ),
551 );
552 }
553
554 /**
555 * Converts a list of taxonomy terms into checkboxes and displays them in columns
556 * @param $elements A form element that contains the checkboxes to be themed
557 * @return HTML
558 */
559 function theme_syndication_taxonomy_builder_columns_checkboxes($element) {
560 $options = $element['#options'];
561 if (count($options) < $element['#columns']) {
562 $element['#columns'] = 1; //if there are less terms than columns then put them in one column
563 }
564 $rows = array();
565 foreach ($options as $key => $value) {
566 $row[] = drupal_render($element[$key]);
567 if (count($row) == $element['#columns']) {
568 array_push($rows,$row);
569 $row = array();
570 }
571 }
572 // This flushes out the columns when the items don't divide evenly into the columns.
573 if (count($row)) {
574 array_push($rows,$row);
575 }
576 return theme('table', NULL, $rows);
577 }
578
579 /**
580 * Display data into columns
581 * @param $data Array of data. One element per column
582 * @return HTML
583 */
584 function theme_syndication_columns($data = array()) {
585 $cols = count($data);
586 $width = (int)((100/$cols) - 1); // make this a fraction smaller so the percentages won't add up to more than 100%
587 foreach ($data as $col) {
588 $output .= "<div class='syndication-column' style='width:$width%'>";
589 $output .= $col;
590 $output .= "</div>";
591 }
592 $output .= '<div class="syndication-clear"></div>';
593 return $output;
594 }

  ViewVC Help
Powered by ViewVC 1.1.2