Feeds are based on content-types. Default content types are created on install. You can create new content types on the admin/content/types/add page. To do that, enable the "Is a feed content type" checkbox under the Feed API group on the content type edit form. Then choose the processors and parsers that you would like to use. At least one parser and one processor must be enabled. '); case 'admin/settings/feedapi': return t("You can find more configuration options on the content type edit form of !admin-link.", array('!admin-link' => l(t('FeedAPI-enabled content-types'), 'admin/content/types'))); } } /** * Implementation of hook_menu(). */ function feedapi_menu() { $items['admin/content/feed'] = array( 'title' => 'Feeds', 'description' => "Overview which content your site aggregates from other sites and see detailed statistics about the feeds.", 'page callback' => 'feedapi_management_page', 'access callback' => TRUE, //'access arguments' => array('administer feedapi'), ); $items['admin/content/feed/list'] = array( 'title' => t('List'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'access' => user_access('administer feedapi'), 'weight' => -15, ); $items['admin/content/feed/import_opml'] = array( 'title' => t('Import OPML'), 'access' => user_access('administer feedapi'), 'page callback' => 'drupal_get_form', 'page arguments' => array('feedapi_import_feeds_form'), ); $items['admin/content/feed/export_opml'] = array( 'title' => t('Export all feeds as OPML'), 'access' => user_access('administer feedapi'), 'page callback' => 'drupal_get_form', 'page arguments' => array('_feedapi_export_opml'), ); $items['admin/settings/feedapi'] = array( 'title' => t('FeedAPI settings'), 'page callback' => 'drupal_get_form', 'page arguments' => array('feedapi_admin_settings'), 'access' => user_access('administer feedapi'), ); $items['node/%node/refresh'] = array( 'title' => t('Refresh'), 'page callback' => 'feedapi_refresh', 'page arguments' => array(1), 'type' => MENU_LOCAL_TASK, 'access callback' => 'feedapi_access_op', 'access arguments' => array(1), ); $items['node/%node/purge'] = array( 'title' => t('Remove items'), 'page callback' => 'feedapi_invoke_feedapi', 'page arguments' => array("purge", 1, 'items'), 'type' => MENU_LOCAL_TASK, 'access callback' => 'feedapi_access_op', 'access arguments' => array(1), ); return $items; } function feedapi_access_op($nid) { $node = node_load($nid); $own_feed = $node->uid == $user->uid && user_access('edit own '. $node->type . ' content') ? TRUE : FALSE; return user_access('administer feedapi') || $own_feed; } /** * Implementation of hook_nodeapi(). */ function feedapi_nodeapi(&$node, $op, $teaser, $page) { if (isset($node->feed) || feedapi_enabled($node->type)) { switch ($op) { case 'insert': _feedapi_insert($node, $teaser, $page); break; case 'update': _feedapi_update($node, $teaser, $page); break; case 'load': if ($feed = db_fetch_object(db_query('SELECT * FROM {feedapi} WHERE nid = %d', $node->nid))) { $node->feed = $feed; $node->feed->nid = $node->nid; $node->feed->settings = _feedapi_get_settings(array('node_type' => $node->type, 'nid' => $node->nid)); // Load parsers and processors from content type $node_type_settings = _feedapi_get_settings(array('node_type' => $node->type)); $node->feed->parsers = _feedapi_format_settings($node_type_settings, 'parsers'); $node->feed->processors = _feedapi_format_settings($node_type_settings, 'processors'); } break; case 'delete': // Could be a performance problem - think of thousands of node feed items. // This is a temporary status. See: http://drupal.org/node/195723 // feedapi_invoke_feedapi('purge', $node->feed); db_query("DELETE FROM {feedapi_stat} WHERE id = %d", $node->nid); db_query("DELETE FROM {feedapi} WHERE nid = %d", $node->nid); break; case 'presave': // Todo: the first case essentially copies the entire feed array from feedapi to feed. // Figure out a way how to save this step. $node->feed = isset($node->feedapi_object) ? $node->feedapi_object : _feedapi_build_feed_object($node->type, $node->feedapi['feedapi_url']); break; } } } /** * Implementation of hook_node_type(). */ function feedapi_node_type($op, $info) { switch ($op) { case 'delete': variable_del('feedapi_settings_'. $info->type); variable_del('feedapi_'. $info->type); break; case 'update': if (!empty($info->old_type) && $info->old_type != $info->type) { $setting = variable_get('feedapi_settings_'. $info->old_type, array()); variable_del('feedapi_settings_'. $info->old_type); variable_set('feedapi_settings_'. $info->type, $setting); } break; } } /** * Implementation of hook_block(). */ function feedapi_block($op = 'list', $delta = 0) { $blocks = array(); $names = _feedapi_content_types_list(); switch ($op) { case 'list': foreach ($names as $type => $name) { $blocks[$type]['info'] = t('FeedAPI: Quick create !preset', array('!preset' => $name)); $blocks['type']['cache'] = BLOCK_CACHE_GLOBAL; } break; case 'view': if (node_access('create', $delta)) { $blocks['subject'] = t('Create !preset', array('!preset' => $names[$delta])); $blocks['content'] = drupal_get_form('feedapi_simplified_form', $delta); } break; } return $blocks; } /** * Implementation of hook_perm(). */ function feedapi_perm() { return array('administer feedapi', 'advanced feedapi options'); } /** * Implementation of hook_link(). */ function feedapi_link($type, $node = NULL) { if ($type == 'node' && isset($node->feed)) { if (strlen($node->feed->link) > 0) { $links['feedapi_original'] = array( 'title' => t('Link to site'), 'href' => $node->feed->link, ); return $links; } } } /** * Invoke feedapi API callback functions. * * @param $op * "load" Load the feed items basic data into the $feed->items[] * "refresh" Re-download the feed and process newly arrived item * "purge" Delete all the feed items * * @param $feed * A feed object. If only the ID is known, you should pass something like this: $feed->nid = X * @param $param * Depends on the $op value. */ function feedapi_invoke_feedapi($op, &$feed, $param = NULL) { if (!is_object($feed)) { return FALSE; } // The node is passed if (is_object($feed->feed)) { $feed = $feed->feed; } if (!isset($feed->processors)) { $node = node_load($feed->nid); if (!isset($node->feed)) { return FALSE; } $feed = $node->feed; } _feedapi_sanitize_processors($feed); switch ($op) { case 'load': return _feedapi_invoke_load($feed, $param); case 'refresh': return _feedapi_invoke_refresh($feed, $param); case 'purge': return _feedapi_invoke_purge($feed, $param); default: // Other operations return _feedapi_invoke($op, $feed, $param); } } /** * Ask for confirmation before deletig all the items */ function feedapi_purge_confirm($form_state, $node) { $output = confirm_form( array('nid' => array('#type' => hidden, '#value' => $node->nid)), t('Delete all the feed items from !name', array('!name' => $node->title)), 'node/'. $node->nid, t("Are you sure you want to delete all the feed items from !name?", array('!name' => $node->title)), t('Yes'), t('No'), 'feedapi_purge_confirm' ); return $output; } /** * Submitted items purging form. Drop all the items. */ function feedapi_purge_confirm_submit($form, &$form_state) { $feed->nid = $form_state['values']['nid']; feedapi_invoke_feedapi('purge', $feed, 'items_confirmed'); $form_state['redirect'] = 'node/'. $form_state['values']['nid']; } /** * OPML Feed import form, also allows setting defaults to be applied to each feed */ function feedapi_import_feeds_form() { $form['opml'] = array( '#type' => 'file', '#title' => t('OPML File'), '#size' => 50, '#description' => t('Upload an OPML file containing a list of newsfeeds to be imported.'), ); $form['feed_type'] = array( '#type' => 'select', '#title' => t('Feed Type'), '#description' => t("The type of feed you would like to associate this import with."), '#options' => _feedapi_content_types_list(), '#required' => TRUE, ); $form['#attributes']['enctype'] = 'multipart/form-data'; $form['submit'] = array('#type' => 'submit', '#value' => 'Submit'); if (module_exists('og')) { og_form_add_og_audience('feedapi_import_feeds_form', $form); } return $form; } /** * Handle the submission of the OPML import form */ function feedapi_import_feeds_form_submit($form, &$form_state) { $file = file_check_upload('opml'); if ($file = file($file->filepath)) { $file = implode('', $file); if ($count = _feedapi_import_opml_process($file, $form_state['values'])) { drupal_set_message(t('Successfuly imported %count feeds from OPML', array('%count' => $count))); } else { drupal_set_message(t('Feed list could not be imported. Please check that this is a valid OPML file.'), 'error'); } } else { drupal_set_message(t('Data could not be retrieved, invalid or empty file.'), 'error'); } $form_state['redirect'] = 'admin/content/feed'; } /** * Delete expired items and return informations about the feed refreshing * * @param $feed * The feed object * @param $force * Not in use anymore. Will be removed in future releases. * @param $settings * Optional feed settings * @return * FALSE if the feed don't have to be refreshed. (forbidden if the $force is TRUE) */ function feedapi_expire($feed, $force = TRUE, $settings = NULL) { // Backwards compatibility, get settings if not passed $settings = is_null($settings) ? _feedapi_get_settings(array('nid' => $feed->nid)) : $settings; // Each processor can have its own expiration criteria ? $expired = _feedapi_invoke('expire', $feed, $settings); // Return the number of expired items return $expired ? array_sum($expired) : 0; } /** * Callback for expired items. Does the actual deleting */ function feedapi_expire_item($feed, $item) { foreach ($feed->processors as $processor) { module_invoke($processor, 'feedapi_item', 'delete', $item, $feed->nid); } } /** * Implementation of hook_form_alter(). */ function feedapi_form_alter(&$form, &$form_state, $form_id) { // Content type form. if ($form_id == 'node_type_form' && isset($form['identity']['type'])) { if (!$node_type_settings = _feedapi_get_settings(array('node_type' => $form['#node_type']->type))) { $node_type_settings = array(); } $form['#submit'][] = 'feedapi_content_type_submit'; $form['feedapi'] = array( '#type' => 'fieldset', '#title' => t('Feed API'), '#collapsible' => TRUE, '#collapsed' => !$node_type_settings['enabled'], '#tree' => TRUE, '#validate' => array('_feedapi_validate_content_type' => array()), ); $form['feedapi']['enabled'] = array( '#type' => 'checkbox', '#title' => t('Is a feed content type'), '#description' => t('Check if you want to use this content type for downloading feeds to your site.'), '#default_value' => $node_type_settings['enabled'], '#weight' => -15, ); $modules = module_implements('feedapi_settings_form'); foreach ($modules as $module) { $form['feedapi']['defaults'] = array('#type' => 'markup', '#value' => 'Default settings
'),
'#description' => t('The list of tags which are allowed in feeds, i.e., which will not be removed by Drupal.')
);
$form['feedapi_allow_html_all'] = array(
'#type' => 'checkbox', '#title' => t('Allow all HTML tags'),
'#default_value' => variable_get('feedapi_allow_html_all', FALSE),
'#description' => t('In this case the module does\'t filter any HTML elements from the incoming fields. This checkbox overrides the above list of allowed tags.')
);
if (variable_get('feedapi_allow_html_all', FALSE)) {
$form['feedapi_allowed_html_tags']['#disabled'] = TRUE;
}
// Drupal will try to overwrite this value at cron time
$max_exec = !ini_get('safe_mode') ? 240 : ini_get('max_execution_time');
$form['feedapi_cron_percentage'] = array(
'#type' => 'select',
'#title' => t('Cron time for FeedAPI [%]'),
'#options' => drupal_map_assoc(array(15, 25, 50, 75)),
'#default_value' => variable_get('feedapi_cron_percentage', 15),
'#description' => t('Percentage of maximal PHP execution time (currently !exec seconds).
At current settings, the FeedAPI cron process can run for up to !now seconds.',
array("!exec" => $max_exec, "!now" => (variable_get('feedapi_cron_percentage', 15) / 100) * $max_exec)),
);
return system_settings_form($form);
}
/**
* Create a feedapi node programatically.
* @param $param
* Either a feedapi - enabled node type or a $node object with at least valid $node->type.
* @param $url
* URI of feed.
*/
function feedapi_create_node($param, $url) {
if (is_object($param)) {
$node = $param;
}
else {
$node = new stdClass();
$node->type = $param;
}
if (!feedapi_enabled($node->type)) {
return FALSE;
}
$feed = _feedapi_build_feed_object($node->type, $url);
if (!$feed->title && !$node->title) {
return FALSE;
}
module_load_include('inc', 'node', 'node.pages');
$node->title = $node->title ? $node->title : $feed->title;
$node->body = $node->body ? $node->body : $feed->description;
$node->feedapi_object = $feed;
$node_options = variable_get('node_options_'. $node->type, array('status', 'promote'));
// If this is a new node, fill in the default values.
foreach (array('status', 'promote', 'sticky') as $key) {
$node->$key = in_array($key, $node_options);
}
// Get the content-type settings as default
$node->feedapi = _feedapi_get_settings(array('node_type' => $node->type));
node_object_prepare($node);
global $user;
$node->uid = $user->uid;
node_save($node);
return $node;
}
/**
* Load node by URL.
* @param $args
* Currently only supported $args['url] - URL string.
* @return
* Node object if successful, FALSE if not.
*/
function feedapi_load_node($args) {
if ($nid = db_result(db_query("SELECT nid FROM {feedapi} WHERE url = '%s'", $args['url']))) {
return node_load($nid);
}
return FALSE;
}
/**
* Refresh a feed node (= run enabled processors on it).
* @param $node
* A node object with a $node->feed object.
* @param $destination_path
* If a destination path is given, function redirects to this destination.
*/
function feedapi_refresh($node, $destination_path = NULL) {
feedapi_invoke_feedapi('refresh', $node->feed, FALSE);
if ($destination_path) {
drupal_goto($destination_path);
}
else {
drupal_goto('node/'. $node->nid);
}
}
/**
* Insert feedapi data to the DB when it's a new for for FeedAPI
*/
function _feedapi_insert(&$node, $teaser, $page) {
if (isset($node->feed->url) && isset($node->feed->feed_type)) {
db_query("INSERT INTO {feedapi} (
nid, url, link, feed_type, processors,
parsers, checked, settings) VALUES
(%d, '%s', '%s', '%s', '%s', '%s', %d, '%s')",
$node->nid,
$node->feed->url,
$node->feed->options->link,
$node->feed->feed_type,
serialize($node->feed->processors),
serialize($node->feed->parsers),
0,
serialize(array())
);
// Store add on module's settings if user has permission to do so.
if (user_access('advanced feedapi options')) {
_feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
}
// Refresh feed if the user would like to do that
if ($node->feedapi['refresh_on_create'] == TRUE) {
$node->feed->nid = $node->nid;
feedapi_invoke_feedapi('refresh', $node->feed);
}
}
}
/**
* Update feed data of an existing feed
*/
function _feedapi_update(&$node, $teaser, $page) {
if (isset($node->feed)) {
$old_config = node_load($node->nid);
// In that case this feed has never have feed data. Should be created then, this is not really an update
if (!is_numeric($old_config->feed->nid)) {
$node->feed = _feedapi_build_feed_object($node->type, $node->feed->url);
_feedapi_insert($node, 'insert', $teaser, $page);
return;
}
foreach ($old_config->feed->processors as $processor) {
if (!in_array($processor, $node->feed->processors)) {
$items = module_invoke($processor, 'feedapi_item', 'fetch', $node->feed);
foreach ($items as $item) {
module_invoke($processor, 'feedapi_item', 'delete', $item);
}
}
}
db_query("UPDATE {feedapi} SET
url = '%s', feed_type = '%s', processors = '%s',
parsers = '%s', link = '%s' WHERE nid = %d",
$node->feed->url,
$node->feed->feed_type,
serialize($node->feed->processors),
serialize($node->feed->parsers),
$node->feed->options->link,
$node->nid
);
// Store add on module's settings if user has permission to do so.
if (user_access('advanced feedapi options')) {
_feedapi_store_settings(array('nid' => $node->nid), $node->feedapi);
}
}
}
/**
* Execute the enabled parsers and create an unified output
*
* @param $feed
* Feed object
* @param $parsers
* Structure: array(
* "primary" => "parser_primary",
* "secondary" => array("parser1", "parser2", "parserN")
* );
* @return
* The object of the parser data
*/
function _feedapi_call_parsers($feed, $parsers) {
$nid = $feed->nid;
$parser_primary = array_shift($parsers);
$parsers_secondary = $parsers;
if (module_exists($parser_primary)) {
$feed->feed_type = module_invoke($parser_primary, 'feedapi_feed', 'compatible', $feed);
$parser_output = module_invoke($parser_primary, 'feedapi_feed', 'parse', $feed);
if ($parser_output === FALSE) {
return $parser_output;
}
$feed = (object) array_merge((array) $feed, (array) $parser_output);
}
// Call the turned on parsers, create a union of returned options
$parsers_secondary = is_array($parsers_secondary) ? $parsers_secondary : array();
foreach ($parsers_secondary as $parser) {
$feed_ext = module_invoke($parser, 'feedapi_feed', 'parse', $feed, FALSE);
$feed->options = (object) ((array) $feed->options + (array) $feed_ext->options);
// Merge items' options
foreach ($feed_ext->items as $key => $item) {
$feed->items[$key]->options = (object) ((array) $feed->items[$key]->options + (array) $item->options);
}
}
$feed->nid = $nid;
foreach (module_implements('feedapi_after_parse') as $module) {
$func = $module. '_feedapi_after_parse';
$func($feed);
}
// Filter bad or not allowed tags, sanitize data (currently timestamp checking)
if (!variable_get('feedapi_allow_html_all', FALSE)) {
$allowed = preg_split('/\s+|<|>/', variable_get('feedapi_allowed_html_tags', '
'), -1, PREG_SPLIT_NO_EMPTY);
foreach (array('title', 'description') as $property) {
if (isset($feed->{$property})) {
if (is_string($feed->{$property})) {
$feed->{$property} = filter_xss($feed->{$property}, $allowed);
}
}
}
for ($i = 0; $i < count($feed->items); $i++) {
$feed->items[$i]->title = filter_xss($feed->items[$i]->title, $allowed);
$feed->items[$i]->description = filter_xss($feed->items[$i]->description, $allowed);
if ($feed->items[$i]->options->timestamp == 0) {
$feed->items[$i]->options->timestamp = time();
}
}
}
return $feed;
}
/**
* Stores settings per content type or per node.
*
* @param $args
* Associative array which is $args['nid'] = N or $args['node_type'] = "content_type". Depends on what to store for
* @param $settings
* The settings data itself
*/
function _feedapi_store_settings($args, $settings) {
if ($args['nid']) {
db_query("UPDATE {feedapi} SET settings = '%s' WHERE nid = %d", serialize($settings), $args['nid']);
module_invoke_all('feedapi_after_settings', $args['nid'], $settings);
// This ensures that next time, not the cached, but the updated value will be used.
static $node_settings;
unset($node_settings[$args['nid']]);
}
elseif ($args['node_type']) {
variable_set('feedapi_settings_'. $args['node_type'], $settings);
}
}
/**
* Determines wether feedapi is enabled for given node type.
* If parser or processor is passed in, this function determines wether given
* parser or processor is enabled for given node type.
* @param $node_type
* A Drupal node type.
* @param $parser_or_processor
* A parser or processor - pass in by module name.
* @return TRUE if enabled, FALSE if not.
*/
function feedapi_enabled($node_type, $parser_or_processor = '') {
$settings = _feedapi_get_settings(array('node_type' => $node_type));
if (!$parser_or_processor || !$settings['enabled']) {
return $settings['enabled'] ? TRUE : FALSE;
}
foreach (array('parsers', 'processors') as $stage) {
if ($settings[$stage][$parser_or_processor]['enabled']) {
return TRUE;
}
}
return FALSE;
}
/**
* Helper function for feedapi_invoke().
*
* Generic operations, collects results and returns array
*/
function _feedapi_invoke($op, &$feed, $param) {
$output = array();
foreach ($feed->processors as $processor) {
$result = module_invoke($processor, 'feedapi_item', $op, $feed, $param);
// Result may be a list of items or single values (count)
if ($result) {
if (is_array($result)) {
$output = array_merge($output, $result);
} else {
$output[] = $result;
}
}
}
return $output;
}
/**
* Helper function for feedapi_invoke().
* Load a list of feed items into the feed object from the processors.
*/
function _feedapi_invoke_load(&$feed, $param) {
$feed->items = array();
foreach ($feed->processors as $processor) {
$items = module_invoke($processor, 'feedapi_item', 'fetch', $feed);
if (is_array($items)) {
foreach ($items as $item) {
$feed->items[] = $item;
}
}
}
}
/**
* Helper function for feedapi_invoke().
* Refresh the feed, call the proper parsers and processors' hooks.
* Don't call this function directly, use feedapi_refresh() instead.
*
* @ TODO Fix: This may loop forever when a feed has no processors
*/
function _feedapi_invoke_refresh(&$feed, $param) {
$timestamp = variable_get('cron_semaphore', FALSE) !== FALSE ? variable_get('cron_semaphore', FALSE) : time();
$counter = array();
timer_start('feedapi_'. $feed->nid);
$cron = $param;
// Step 0: Check processors and grab settings
if (!is_array($feed->processors) || count($feed->processors) == 0) {
if (!$cron) {
drupal_set_message(t("No processors specified for URL %url. Could not refresh.", array('%url' => $feed->url)), "error");
drupal_goto('node/'. $feed->nid);
}
return 0;
}
$settings = _feedapi_get_settings(array('nid' => $feed->nid));
// Step 1: Force processors to delete old items and determine the max. create elements.
$counter['expired'] = feedapi_expire($feed);
// Step 2: Get feed.
$nid = $feed->nid;
$hash_old = $feed->hash;
$feed = _feedapi_call_parsers($feed, $feed->parsers, $feed->half_done);
if (is_object($feed)) {
$feed->hash = md5(serialize($feed->items));
}
// Step 3: See, whether feed has been modified.
if ($feed === FALSE || $hash_old == $feed->hash) {
// Updated the checked field in any case.
db_query("UPDATE {feedapi} SET checked = %d, half_done = %d WHERE nid = %d", time(), FALSE, $nid);
if (!$cron) {
if ($hash_old == $feed->hash && is_object($feed)) {
drupal_set_message(t('There are no new items in the feed.'), 'status');
}
else {
drupal_set_message(t('Could not refresh feed.'), 'error');
}
}
return $counter;
}
// Step 4: Walk through the items and check duplicates, then save or update
$items = $feed->items;
$updated = 0;
$new = 0;
$half_done = FALSE;
// We check for time-out after each item
foreach ($items as $index => $item) {
// Call each item parser
$item->is_updated = FALSE;
$item->is_new = FALSE;
foreach ($feed->processors as $processor) {
if (!module_invoke($processor, 'feedapi_item', 'unique', $item, $feed->nid, $feed->settings['processors'][$processor])) {
if ($settings['update_existing'] == TRUE) {
module_invoke($processor, 'feedapi_item', 'update', $item, $feed->nid, $feed->settings['processors'][$processor]);
$item->is_updated = TRUE;
}
}
else {
// We have checked before for expired items, so just save it.
// if the item is already expired then do nothing
$items_delete = $settings['items_delete'];
$diff = abs(time() - (isset($item->options->timestamp) ? $item->options->timestamp : time()));
if ($diff > $items_delete && ($items_delete > FEEDAPI_NEVER_DELETE_OLD)) {
break;
}
module_invoke($processor, 'feedapi_item', 'save', $item, $feed->nid, $feed->settings['processors'][$processor]);
$item->is_new = TRUE;
}
}
$new = $item->is_new ? $new + 1 : $new;
$updated = ($item->is_updated && !$item->is_new) ? $updated + 1 : $updated;
// Decision on time. If the exec time is greather than the user-set percentage of php max execution time
if ($cron && !feedapi_cron_time()) {
$half_done = ($new + $updated) == count($items) ? FALSE : TRUE;
break;
}
// Save the item status for further processing
$feed->items[$index] = $item;
}
// Closing step: Call after refresh and update feed statistics
foreach (module_implements('feedapi_after_refresh') as $module) {
$func = $module. '_feedapi_after_refresh';
$func($feed);
}
if ($new > 0) {
_feedapi_store_stat($nid, 'update_times', time(), $timestamp);
_feedapi_store_stat($nid, 'new', $new, $timestamp);
_feedapi_store_stat($nid, 'download_num', count($items), $timestamp);
_feedapi_store_stat($nid, 'process_time', timer_read('feedapi_'. $feed->nid), $timestamp);
}
db_query("UPDATE {feedapi} SET checked = %d, half_done = %d, hash = '%s' WHERE nid = %d", time(), $half_done, $feed->hash, $feed->nid);
if (!$cron) {
if ($new == 0 && $updated == 0) {
drupal_set_message(t('There are no new items in the feed.'), 'status');
} else {
drupal_set_message(t("%new new item(s) were saved. %updated existing item(s) were updated.", array("%new" => $new, "%updated" => $updated)));
}
// @ TODO what value to return here?
} else {
// Update and return counter
$counter['new'] = $new;
$counter['updated'] = $updated;
return $counter;
}
}
/**
* Helper function for feedapi_invoke().
* Delete all feed items of a feed.
*/
function _feedapi_invoke_purge(&$feed, $param) {
$node = node_load($feed->nid);
// Reset hash.
db_query("UPDATE feedapi SET hash = 0 WHERE nid = %d", $feed->nid);
if ($param == 'items') {
return drupal_get_form('feedapi_purge_confirm', $node);
}
feedapi_invoke_feedapi('load', $feed);
// Delete items from the processors
foreach ($feed->items as $item) {
foreach($feed->processors as $processor) {
// FIXME: it's possible now to accidentally delete an item from another processor
module_invoke($processor, 'feedapi_item', 'delete', $item, $feed->settings['processors'][$processor]);
}
}
if ($param == 'items_confirmed') {
drupal_set_message(t('!count feed items have been deleted successfully from the feed.', array('!count' => count($feed->items))));
}
}
/**
* Builds feed object ready to be sticked onto node.
*/
function _feedapi_build_feed_object($node_type, $url) {
$feed = new stdClass();
$feed->url = $url;
$node_type_settings = _feedapi_get_settings(array('node_type' => $node_type));
$feed->processors = _feedapi_format_settings($node_type_settings, 'processors');
$feed->parsers = _feedapi_format_settings($node_type_settings, 'parsers');
if ($feed->url) {
$feed = _feedapi_call_parsers($feed, $feed->parsers);
}
$feed->link = $feed->options->link;
return $feed;
}
/**
* Returns per content type settings ordered by weight
* and only those that are turned on.
* @param $node_type_settings
* Content type settings retrieved with _feedapi_get_settings().
* @param $stage_type
* 'parsers' or 'processors'
*/
function _feedapi_format_settings($node_type_settings, $stage_type) {
$result = array();
$settings = $node_type_settings[$stage_type];
foreach ($settings as $name => $properties) {
if ($settings[$name]['enabled']) {
$result[$settings[$name]['weight']] = $name;
}
}
ksort($result);
return $result;
}
/**
* Retrieve settings per content type or per node.
* @param $args
* Array in the format of:
* $args = array(
* 'node_type' => '