summaryrefslogtreecommitdiffstats
path: root/views_rss.module
blob: b1a415b680c88aa2a0361d926135d46c20294075 (plain)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
<?php
// $Id$

/**
 * Provide views plugins for the feed types we support.
 */
function views_rss_views_style_plugins() {
  return array(
    'views_rss' => array(
      'name' => t('Views RSS: RSS feed'),
      'theme' => 'views_rss_feed',
      'needs_table_header' => TRUE,
      'needs_fields' => TRUE,
      'even_empty' => TRUE,
    ),
  );
}

/**
 * While we support the global selector, some might want to allow
 * ONLY RSS feeds so we support a stingy selector too
 */
function views_rss_views_arguments() {
  $arguments = array(
    'rss_feed' => array(
      'name' => t('RSS: RSS Feed Selector'),
      'handler' => 'views_handler_arg_rss_feed',
      'help' => t('This argument specifies a specific RSS feed selector; it will only select RSS feeds, unlike the built-in selector which can select pluggable feeds.'),
    ),
  );
  return $arguments;
}

/**
 * handler for our own RSS argument; mimics the feed selector
 */
function views_handler_arg_rss_feed($op, &$query, $argtype, $arg = '') {
  switch($op) {
    case 'summary':
    case 'sort':
    case 'link':
    case 'title':
      break;
    case 'filter':
      // This is a clone of the default selector, but it just invokes ours
      // rather than calling all of them.
      views_rss_views_feed_argument('argument', $GLOBALS['current_view'], $arg);
  }
}

/**
 * post view for our own op -- mimics the feed selector
 */
function views_rss_views_post_view($view, $items, $output) {
  foreach ($view->argument as $id => $argument) {
    if ($argument['type'] == 'rss_feed') {
      $feed = $id;
      break;
    }
  }

  if ($feed !== NULL) {
    return views_rss_views_feed_argument('post_view', $view, 'rss_feed');
  }
}

/**
 * feed argument hook that will convert us to RSS or display an icon.
 * the 4th argument isn't part of the hook, but we use it to differentiate
 * when called as a hook or when called manually from views_rss_views_post_view
 */
function views_rss_views_feed_argument($op, &$view, $arg) {
  if ($op == 'argument' && $arg == 'feed') {
    $view->page_type = 'views_rss';
  }
  else if ($op == 'post_view') {
    $args = views_post_view_make_args($view, $arg, 'feed');
    $url = views_get_url($view, $args);
    $title = views_get_title($view, 'page', $args);

    if ($view->used_filters) {
      $filters = drupal_query_string_encode($view->used_filters);
    }

    drupal_add_feed(url($url, $filters), $title);
  }
}

/**
 * plugin that actually displays an RSS feed
 */
function theme_views_rss_feed($view, $nodes, $type) {
  if ($type == 'block') {
    return;
  }
  global $base_url;

  $channel = array(
    // a check_plain isn't required on these because format_rss_channel
    // already does this.
    'title'       => views_get_title($view, 'page'),
    'link'        => url($view->real_url, NULL, NULL, true),
    'description' => $view->description,
  );

  $item_length = variable_get('feed_item_length', 'teaser');
  $namespaces = array('xmlns:dc="http://purl.org/dc/elements/1.1/"');

  // Except for the original being a while and this being a foreach, this is
  // completely cut & pasted from node.module.
  foreach ($nodes as $node) {
    // Load the specified node:
    $item = node_load($node->nid);
    $link = url("node/$node->nid", NULL, NULL, 1);

    if ($item_length != 'title') {
      $teaser = ($item_length == 'teaser') ? TRUE : FALSE;

      // Filter and prepare node teaser
      if (node_hook($item, 'view')) {
        node_invoke($item, 'view', $teaser, FALSE);
      }
      else {
        $item = node_prepare($item, $teaser);
      }

      // Allow modules to change $node->teaser before viewing.
      node_invoke_nodeapi($item, 'view', $teaser, FALSE);
    }

    // Allow modules to add additional item fields
    $extra = node_invoke_nodeapi($item, 'rss item');
    $extra = array_merge($extra, array(array('key' => 'pubDate', 'value' =>  date('r', $item->created)), array('key' => 'dc:creator', 'value' => $item->name), array('key' => 'guid', 'value' => $item->nid . ' at ' . $base_url, 'attributes' => array('isPermaLink' => 'false'))));
    foreach ($extra as $element) {
      if ($element['namespace']) {
        $namespaces = array_merge($namespaces, $element['namespace']);
      }
    }
    
    // Prepare the item description
    switch ($item_length) {
      case 'fulltext':
        $item_text = $item->body;
        break;
      case 'teaser':
        $item_text = $item->teaser;
        if ($item->readmore) {
          $item_text .= '<p>'. l(t('read more'), 'node/'. $item->nid, NULL, NULL, NULL, TRUE) .'</p>';
        }
        break;
      case 'title':
        $item_text = '';
        break;
    }

    $items .= format_rss_item($item->title, $link, $item_text, $extra);
  }

  $channel_defaults = array(
    'version'     => '2.0',
    'title'       => variable_get('site_name', 'drupal') .' - '. variable_get('site_slogan', ''),
    'link'        => $base_url,
    'description' => variable_get('site_mission', ''),
    'language'    => $GLOBALS['locale'],
  );
  $channel = array_merge($channel_defaults, $channel);

  $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
  $output .= "<rss version=\"". $channel["version"] . "\" xml:base=\"". $base_url ."\" ". implode(' ', $namespaces) .">\n";
  $output .= format_rss_channel($channel['title'], $channel['link'], $channel['description'], $items, $channel['language']);
  $output .= "</rss>\n";

  drupal_set_header('Content-Type: text/xml; charset=utf-8');
  print $output;
  module_invoke_all('exit');
  exit; 
}