aggregator.module 7.97 KB
Newer Older
1
<?php
Dries's avatar
Dries committed
2

Dries's avatar
Dries committed
3 4
/**
 * @file
5
 * Used to aggregate syndicated content (RSS, RDF, and Atom).
Dries's avatar
Dries committed
6 7
 */

8
use Drupal\aggregator\FeedInterface;
9
use Drupal\Component\Utility\Xss;
10
use Symfony\Component\HttpFoundation\Request;
11

12 13 14
/**
 * Denotes that a feed's items should never expire.
 */
15
const AGGREGATOR_CLEAR_NEVER = 0;
16

Dries's avatar
Dries committed
17
/**
18
 * Implements hook_help().
Dries's avatar
Dries committed
19
 */
20 21 22
function aggregator_help($route_name, Request $request) {
  switch ($route_name) {
    case 'help.page.aggregator':
23 24
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
25
      $output .= '<p>' . t('The Aggregator module is an on-site syndicator and news reader that gathers and displays fresh content from RSS-, RDF-, and Atom-based feeds made available across the web. Thousands of sites (particularly news sites and blogs) publish their latest headlines in feeds, using a number of standardized XML-based formats. For more information, see the <a href="!aggregator-module">online documentation for the Aggregator module</a>.', array('!aggregator-module' => 'https://drupal.org/documentation/modules/aggregator')) . '</p>';
26 27 28
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Viewing feeds') . '</dt>';
29
      $output .= '<dd>' . t('Users view feed content in the <a href="!aggregator">main aggregator display</a>, or by <a href="!aggregator-sources">their source</a> (usually via an RSS feed reader). The most recent content in a feed can be displayed as a block through the <a href="!admin-block">Blocks administration page</a>.', array('!aggregator' => \Drupal::url('aggregator.page_last'), '!aggregator-sources' => \Drupal::url('aggregator.sources'), '!admin-block' => \Drupal::url('block.admin_display'))) . '</dd>';
30
      $output .= '<dt>' . t('Adding, editing, and deleting feeds') . '</dt>';
31 32 33
      $output .= '<dd>' . t('Administrators can add, edit, and delete feeds, and choose how often to check each feed for newly updated items on the <a href="!feededit">Feed aggregator administration page</a>.', array('!feededit' => \Drupal::url('aggregator.admin_overview'))) . '</dd>';
      $output .= '<dt>' . t('<abbr title="Outline Processor Markup Language">OPML</abbr> integration') . '</dt>';
      $output .= '<dd>' . t('A <a href="!aggregator-opml">machine-readable OPML file</a> of all feeds is available. OPML is an XML-based file format used to share outline-structured information such as a list of RSS feeds. Feeds can also be <a href="!import-opml">imported via an OPML file</a>.', array('!aggregator-opml' => \Drupal::url('aggregator.opml_page'), '!import-opml' => \Drupal::url('aggregator.opml_add'))) . '</dd>';
34
      $output .= '<dt>' . t('Configuring cron') . '</dt>';
35
      $output .= '<dd>' . t('A correctly configured <a href="!cron">cron maintenance task</a> is required to update feeds automatically.', array('!cron' => \Drupal::url('system.cron_settings'))) . '</dd>';
36
      $output .= '</dl>';
37
      return $output;
38 39

    case 'aggregator.admin_overview':
40 41
      // Don't use placeholders for possibility to change URLs for translators.
      $output = '<p>' . t('Thousands of sites (particularly news sites and blogs) publish their latest headlines and posts in feeds, using a number of standardized XML-based formats. Formats supported by the aggregator include <a href="http://cyber.law.harvard.edu/rss/">RSS</a>, <a href="http://www.w3.org/RDF/">RDF</a>, and <a href="http://www.atomenabled.org">Atom</a>.') . '</p>';
42
      $output .= '<p>' . t('Current feeds are listed below, and <a href="!addfeed">new feeds may be added</a>. At the <a href="!block">blocks administration page</a> you can enable for each feed the block <em>Aggregator feed</em> that contains the <em>latest items</em> .', array('!addfeed' => \Drupal::url('aggregator.feed_add'), '!block' => \Drupal::url('block.admin_display'))) . '</p>';
43
      return $output;
44 45

    case 'aggregator.feed_add':
46
      return '<p>' . t('Add a feed in RSS, RDF or Atom format. A feed may only have one entry.') . '</p>';
47 48

    case 'aggregator.opml_add':
49
      return '<p>' . t('<abbr title="Outline Processor Markup Language">OPML</abbr> is an XML format used to exchange multiple feeds between aggregators. A single OPML document may contain a collection of many feeds. Drupal can parse such a file and import all feeds at once, saving you the effort of adding them manually. You may either upload a local file from your computer or enter a URL where Drupal can download it.') . '</p>';
Dries's avatar
Dries committed
50
  }
51 52
}

53
/**
54
 * Implements hook_theme().
55 56 57
 */
function aggregator_theme() {
  return array(
58
    'aggregator_feed_source' => array(
59
      'variables' => array('aggregator_feed' => NULL, 'view_mode' => NULL),
60
      'file' => 'aggregator.theme.inc',
61
      'template' => 'aggregator-feed-source',
62 63
    ),
    'aggregator_block_item' => array(
64
      'variables' => array('item' => NULL, 'feed' => 0),
65
      'file' => 'aggregator.theme.inc',
66
      'template' => 'aggregator-block-item',
67
    ),
68
    'aggregator_summary_items' => array(
69
      'variables' => array('summary_items' => NULL, 'source' => NULL),
70
      'file' => 'aggregator.theme.inc',
71 72
      'template' => 'aggregator-summary-items',
    ),
73
    'aggregator_summary_item' => array(
74
      'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL),
75
      'file' => 'aggregator.theme.inc',
76
      'template' => 'aggregator-summary-item',
77
    ),
78
    'aggregator_item' => array(
79
      'variables' => array('aggregator_item' => NULL, 'view_mode' => NULL),
80
      'file' => 'aggregator.theme.inc',
81 82 83
      'template' => 'aggregator-item',
    ),
    'aggregator_page_opml' => array(
84
      'variables' => array('feeds' => NULL),
85
      'file' => 'aggregator.theme.inc',
86 87
    ),
    'aggregator_page_rss' => array(
88
      'variables' => array('feeds' => NULL),
89
      'file' => 'aggregator.theme.inc',
90 91
    ),
  );
92
}
93

Dries's avatar
Dries committed
94
/**
95
 * Implements hook_permission().
Dries's avatar
Dries committed
96
 */
97
function aggregator_permission() {
98
  return array(
99 100 101 102
    'administer news feeds' => array(
      'title' => t('Administer news feeds'),
    ),
    'access news feeds' => array(
103
      'title' => t('View news feeds'),
104
    ),
105
  );
Dries's avatar
Dries committed
106 107
}

Dries's avatar
Dries committed
108
/**
109
 * Implements hook_cron().
Dries's avatar
Dries committed
110
 *
111
 * Queues news feeds for updates once their refresh interval has elapsed.
Dries's avatar
Dries committed
112
 */
Dries's avatar
Dries committed
113
function aggregator_cron() {
114
  $queue = \Drupal::queue('aggregator_feeds');
115

116
  $result = \Drupal::entityManager()->getStorage('aggregator_feed')->getFeedIdsToRefresh();
117
  foreach ($result as $fid) {
118
    $feed = aggregator_feed_load($fid);
119 120
    if ($queue->createItem($feed)) {
      // Add timestamp to avoid queueing item more than once.
121
      $feed->setQueuedTime(REQUEST_TIME);
122
      $feed->save();
123
    }
Dries's avatar
Dries committed
124
  }
125

126
  // Delete queued timestamp after 6 hours assuming the update has failed.
127
  $result = \Drupal::entityQuery('aggregator_feed')
128 129
    ->condition('queued', REQUEST_TIME - (3600 * 6), '<')
    ->execute();
130 131 132 133 134 135 136 137

  if ($result) {
    $feeds = entity_load_multiple('aggregator_feed', $result);
    foreach ($feeds as $feed) {
      $feed->setQueuedTime(0);
      $feed->save();
    }
  }
Dries's avatar
Dries committed
138 139
}

140
/**
141
 * Implements hook_queue_info().
142
 */
143
function aggregator_queue_info() {
144
  $queues['aggregator_feeds'] = array(
145
    'title' => t('Aggregator refresh'),
146 147 148
    'worker callback' => function (FeedInterface $feed) {
      $feed->refreshItems();
    },
149 150 151
    'cron' => array(
      'time' => 60,
    ),
152 153 154 155
  );
  return $queues;
}

156
/**
157
 * Loads an aggregator feed.
158
 *
159
 * @param int $fid
160
 *   The feed id.
161
 *
162
 * @return \Drupal\aggregator\FeedInterface
163
 *   An object describing the feed.
164
 */
165
function aggregator_feed_load($fid) {
166
  return entity_load('aggregator_feed', $fid);
167 168
}

169
/**
170
 * Renders the HTML content safely, as allowed.
171 172 173
 *
 * @param $value
 *   The content to be filtered.
174
 *
175 176
 * @return
 *   The filtered content.
177 178
 */
function aggregator_filter_xss($value) {
179
  return Xss::filter($value, preg_split('/\s+|<|>/', \Drupal::config('aggregator.settings')->get('items.allowed_html'), -1, PREG_SPLIT_NO_EMPTY));
180
}
181

182
/**
183
 * Implements hook_preprocess_HOOK() for block templates.
184 185
 */
function aggregator_preprocess_block(&$variables) {
186
  if ($variables['configuration']['provider'] == 'aggregator') {
187
    $variables['attributes']['role'] = 'complementary';
188 189
  }
}