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. '); } } /** * Implementation of hook_menu(). */ function feedapi_menu($may_cache) { if ($may_cache) { $items[] = array( 'path' => 'admin/content/feed', 'title' => t('Feeds'), 'description' => t("Overview which content your site aggregates from other sites and see detailed statistics about the feeds."), 'callback' => 'feedapi_management_page', 'access' => user_access('administer feedapi'), ); $items[] = array( 'path' => 'admin/content/feed/list', 'title' => t('List'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'access' => user_access('administer feedapi'), 'weight' => -15, ); $items[] = array( 'path' => 'admin/content/feed/import_opml', 'title' => t('Import OPML'), 'type' => MENU_NORMAL_ITEM, 'access' => user_access('administer feedapi'), 'callback' => 'drupal_get_form', 'callback arguments' => array('feedapi_import_feeds_form'), ); $items[] = array( 'path' => 'admin/content/feed/export_opml', 'title' => t('Import OPML'), 'type' => MENU_CALLBACK, 'access' => user_access('administer feedapi'), 'callback' => 'drupal_get_form', 'callback arguments' => array('_feedapi_export_opml'), ); $items[] = array('path' => 'admin/settings/feedapi', 'title' => t('FeedAPI settings'), 'callback' => 'drupal_get_form', 'callback arguments' => array('feedapi_admin_settings'), 'type' => MENU_NORMAL_ITEM, 'access' => user_access('administer feedapi'), ); } else if (arg(0) == 'node' && is_numeric(arg(1))) { $node = node_load(arg(1)); if (isset($node->feed)) { global $user; $own_feed = $node->uid == $user->uid && user_access('edit own '. $node->type . ' content') ? TRUE : FALSE; $items[] = array('path' => 'node/'. $node->nid. '/refresh', 'title' => t('Refresh'), 'callback' => 'feedapi_invoke_feedapi', 'callback arguments' => array("refresh", $node->feed), 'type' => MENU_LOCAL_TASK, 'access' => (user_access('administer feedapi') || $own_feed), ); $items[] = array('path' => 'node/'. $node->nid. '/purge', 'title' => t('Remove items'), 'callback' => 'feedapi_invoke_feedapi', 'callback arguments' => array("purge", $node->feed, 'items'), 'type' => MENU_LOCAL_TASK, 'access' => (user_access('administer feedapi') || $own_feed), ); } } return $items; } /** * Implementation of hook_nodeapi(). */ function feedapi_nodeapi(&$node, $op, $teaser, $page) { if (isset($node->feed) || feedapi_enabled($node->type)) { switch ($op) { case 'insert': 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. _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi); } break; case 'update': if (isset($node->feed)) { $old_config = node_load($node->nid); 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', items_delete = %d, update_existing = %d WHERE nid = %d", $node->feed->url, $node->feed->feed_type, serialize($node->feed->processors), serialize($node->feed->parsers), $node->feed->options->link, $node->feedapi['feedapi_items_delete'], $node->feedapi['feedapi_update_existing'], $node->nid ); // Store add on module's settings. _feedapi_store_settings(array('nid' => $node->nid), $node->feedapi); } break; case 'load': $node->feed = db_fetch_object(db_query('SELECT * FROM {feedapi} WHERE nid = %d', $node->nid)); $node->feed->settings = _feedapi_get_settings(array('node_type' => $node->type, 'nid' => $node->nid)); $node->feed->statistics = unserialize($node->feed->statistics); // 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. feedapi_invoke_feedapi('purge', $node->feed); db_query("DELETE FROM {feedapi} WHERE nid = %d", $node->nid); break; case 'validate': if (!$node->title) { form_set_error('title', t('Title could not be retrieved from feed.')); } break; case 'submit': // Todo: the first case essentially copies the entire feed array from feedapi to feed. // Figure out a way how to save this step. if ($node->feedapi['feedapi_feed_object']) { $node->feed = $node->feedapi['feedapi_feed_object']; } else { $node->feed = _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); // Todo: find out, why and where there is still feedapi_$info->type being stored. 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) { $names = node_get_types('names'); foreach ($names as $type => $name) { if (!feedapi_enabled($type)) { unset($names[$type]); } } switch ($op) { case 'list': foreach ($names as $type => $name) { $blocks[$type]['info'] = t('FeedAPI: Quick create !preset', array('!preset' => $name)); } return $blocks; case 'view': $block['subject'] = t('Create !preset', array('!preset' => $names[$delta])); $block['content'] = drupal_get_form('feedapi_simplified_form', $delta); return $block; } } /** * 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 (variable_get('feedapi_show_feed_origin_link', TRUE) && strlen($node->feed->link) > 0) { $links['feedapi_original'] = array( 'title' => t('Link to site'), 'href' => $node->feed->link, ); return $links; } } } /** * Implementation of hook_simpletest(). */ function feedapi_simpletest() { $tests = file_scan_directory(drupal_get_path('module', 'feedapi'), '\.test'); return array_keys($tests); } /** * Do various things with feed. Handle the core data and call the * underyling modules (parsers/processors) too. * TODO: Clean up this function, break it in smaller pieces that are * easier to handle. * * @param $op * "load" Load the feed items basic data into the $feed->items[] * "refresh" Re-download the feed and process newly arrived item * * @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; } 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': $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; } } } break; case 'refresh': timer_start('feedapi_'. $feed->nid); $cron = $param; 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; } // Force the processors to delete old items and determine the max. create elements $refresh = feedapi_expire($feed, $cron === TRUE ? FALSE : TRUE); if ($refresh == FALSE) { return; } $nid = $feed->nid; // force non-caching mode if the feed is only processed half-done $feed = _feedapi_call_parsers($feed, $feed->parsers, $feed->half_done ? FALSE : TRUE); if ($feed === FALSE) { // Refresh the Last refresh field at all the cases db_query("UPDATE {feedapi} SET checked = %d, half_done = %d WHERE nid = %d", time(), FALSE, $nid); if (!$cron) { drupal_set_message(t('This feed has not been refreshed after the last check.')); drupal_goto('node/'. $nid); } return; } $items = array_reverse($feed->items); $updated = 0; $new = 0; $half_done = FALSE; // Walk through the items foreach ($items as $item) { // Call each item parser $is_updated = FALSE; $is_new = FALSE; foreach ($feed->processors as $processor) { if (!module_invoke($processor, 'feedapi_item', 'unique', $item, $feed->nid, $feed->settings['processors'][$processor])) { if ($feed->update_existing == TRUE) { module_invoke($processor, 'feedapi_item', 'update', $item, $feed->nid, $feed->settings['processors'][$processor]); $is_updated = TRUE; } } else { module_invoke($processor, 'feedapi_item', 'save', $item, $feed->nid, $feed->settings['processors'][$processor]); $is_new = TRUE; } } $new = $is_new ? $new + 1 : $new; $updated = ($is_updated && !$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 && ((timer_read('feedapi_cron') / 1000) > ((variable_get('feedapi_cron_percentage', 15) / 100) * ini_get('max_execution_time')))) { $timeout = FEEDAPI_TIMEOUT; $half_done = ($new + $updated) == count($items) ? FALSE : TRUE; break; } } foreach (module_implements('feedapi_after_refresh') as $module) { $func = $module. '_feedapi_after_refresh'; $func($feed); } if ($new > 0) { $feed->statistics['update_times'] = _feedapi_queue($feed->statistics['update_times'], time()); $feed->statistics['new'] = _feedapi_queue($feed->statistics['new'], $new); $feed->statistics['download_num'] = _feedapi_queue($feed->statistics['download_num'], count($items)); $feed->statistics['process_time'] = _feedapi_queue($feed->statistics['process_time'], timer_read('feedapi_'. $feed->nid)); } db_query("UPDATE {feedapi} SET checked = %d, statistics = '%s', half_done = %d WHERE nid = %d", time(), serialize($feed->statistics), $half_done, $feed->nid); if (!$cron) { drupal_set_message(t("%new new item(s) were saved. %updated existing item(s) were updated.", array("%new" => $new, "%updated" => $updated))); drupal_goto('node/'. $nid); } if ($timeout) { return $timeout; } break; case 'purge': $node = node_load($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)))); } break; } } /** * Ask for confirmation before deletig all the items */ function feedapi_purge_confirm($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_id, $form_values) { $feed->nid = $form_values['nid']; feedapi_invoke_feedapi('purge', $feed, 'items_confirmed'); drupal_goto('node/'. $form_values['nid']); } /** * OPML Feed import form, also allows setting defaults to be applied to each feed */ function feedapi_import_feeds_form() { global $user; $form['#attributes'] = array('enctype' => 'multipart/form-data'); $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.'), ); $nt = node_get_types(); foreach ($nt as $type => $info) { if (variable_get('feedapi_settings_'. $type, FALSE) !== FALSE) { $feed_types[$type] = $info->name; } } $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' => $feed_types, '#default_value' => '', '#size' => 1, '#required' => TRUE, ); $node = new stdClass(); $node->uid = $user->uid; $form['#node'] = $node; $form['#method'] = 'post'; $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_id, $form_values) { $file = file_check_upload('opml'); if ($file = file($file->filepath)) { $file = implode('', $file); if ($count = _feedapi_import_process($file, $form_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'); } return 'admin/content/feed'; } /** * Delete expired items and return informations about the feed refreshing * * @param $feed * The feed object * @param $force * If TRUE, do not examine that the feed needs refresh * @return * FALSE if the feed don't have to be refreshed. (forbidden if the $force is TRUE) */ function feedapi_expire($feed, $force) { $needs_refresh = time() - $feed->checked > $feed->refresh; if (is_array($feed->items) && ($needs_refresh || $force) && $feed->items_delete != FEEDAPI_NEVER_DELETE_OLD) { foreach ($feed->items as $item) { if (isset($item->arrived) || isset($item->timestamp)) { $diff = abs(time() - (isset($item->arrived) ? $item->arrived : $item->timestamp)); if ($diff > $feed->items_delete) { foreach($feed->processors as $weight) { foreach ($weight as $processor) { module_invoke($processor, 'feedapi_item', 'delete', $item, $feed->nid); } } } } } } if ($needs_refresh == FALSE && $force == FALSE) { return FALSE; } return TRUE; } /** * Implementation of hook_form_alter(). */ function feedapi_form_alter($form_id, &$form) { // Content type form. if ($form_id == 'node_type_form' && isset($form['identity']['type'])) { if (isset($form['#post']['feedapi'])) { // TODO: Drupal automatically stores mutilated 'feedapi_'. $form['#node_type']->type - remove. $type = !empty($form['#node_type']->type) ? $form['#node_type']->type : $form['#post']['type']; _feedapi_store_settings(array('node_type' => $type), $form['#post']['feedapi']); } if (!$node_type_settings = _feedapi_get_settings(array('node_type' => $form['#node_type']->type))) { $node_type_settings = array(); } $form['feedapi'] = array( '#type' => 'fieldset', '#title' => t('Feed API'), '#collapsible' => TRUE, '#collapsed' => !$node_type_settings['enabled'], '#tree' => TRUE, ); $form['feedapi']['enabled'] = array( '#type' => 'checkbox', '#title' => t('Is a feed content type'), '#description' => t('Check this box if you want to use this content type for downloading feeds to your site.'), '#default_value' => $node_type_settings['enabled'], '#weight' => -15, ); $form['feedapi']['parsers'] = array( '#type' => 'fieldset', '#title' => t('Parser settings'), '#description' => t('Parsers turn a feed into an object ready for processing. Choose at least one.'), '#collapsible' => FALSE, '#tree' => TRUE, ); $parsers = module_implements('feedapi_feed', TRUE); rsort($parsers); foreach ($parsers as $parser) { $form['feedapi']['parsers'][$parser] = array( '#type' => 'fieldset', '#title' => feedapi_get_natural_name($parser), '#collapsible' => TRUE, '#collapsed' => !($node_type_settings['parsers'][$parser]['enabled'] || (count($parsers) == 1)), '#tree' => TRUE, '#weight' => $node_type_settings['parsers'][$parser]['weight'], ); $form['feedapi']['parsers'][$parser]['enabled'] = array( '#type' => 'checkbox', '#title' => t('Enable'), '#description' => t('Check this box if you want to enable the @name parser on this feed.', array('@name' => t($parser))), '#default_value' => $node_type_settings['parsers'][$parser]['enabled'] || (count($parsers) == 1), '#weight' => -15, ); $form['feedapi']['parsers'][$parser]['weight'] = array( '#type' => 'weight', '#delta' => 15, '#title' => t('Weight'), '#description' => t('Control the execution order. Parsers with lower weights are called before parsers with higher weights.'), '#default_value' => $node_type_settings['parsers'][$parser]['weight'], '#weight' => -14, ); if ($parser_form = module_invoke($parser, 'feedapi_settings_form', 'parsers')) { $form['feedapi']['parsers'][$parser]['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.')
);
$form['feedapi_show_feed_origin_link'] = array(
'#type' => 'checkbox', '#title' => t('Show originating site link with feed nodes.'),
'#default_value' => variable_get('feedapi_show_feed_origin_link', TRUE),
);
if (variable_get('feedapi_allow_html_all', FALSE)) {
$form['feedapi_allowed_html_tags']['#disabled'] = TRUE;
}
$form['feedapi_statistics_queue'] = array(
'#type' => 'select',
'#title' => t('Number of samples stored per feed for statistics'),
'#options' => drupal_map_assoc(array(10, 20, 50, 100)),
'#default_value' => variable_get('feedapi_statistics_queue', 10),
);
// 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.
*/
function feedapi_create_node($node_type, $url) {
$feed = _feedapi_build_feed_object($node_type, $url);
if (!$feed->title) {
return FALSE;
}
$node = new stdClass();
$node->title = $feed->title;
$node->body = $feed->description;
$node->type = $node_type;
$node->feed = $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);
}
node_object_prepare($node);
global $user;
$node->uid = $user->uid;
node_save($node);
return $node;
}
/**
* Execute the enabled parsers and create an unified output
*
* @param $feed
* Feed object
* @param $cache
* Parser result is cacheable or not
* @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, $cache) {
$nid = $feed->nid;
$parser_primary = array_shift($parsers);
$parsers_secondary = $parsers;
if (module_exists($parser_primary)) {
$parser_output = module_invoke($parser_primary, 'feedapi_feed', 'parse', $feed, $cache);
if ($parser_output === FALSE && $cache) {
return $parser_output;
}
$feed = (object) array_merge((array) $feed, (array) $parser_output);
}
// Call the turned on parsers, create an 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.
*/
function _feedapi_store_settings($args, $settings) {
if ($args['nid']) {
// Filter - only processors and parsers settings will be stored.
$store_settings = array();
if ($settings['processors']) {
$store_settings['processors'] = $settings['processors'];
}
if ($settings['parsers']) {
$store_settings['parsers'] = $settings['parsers'];
}
db_query("UPDATE {feedapi} SET settings = '%s' WHERE nid = %d", serialize($store_settings), $args['nid']);
module_invoke_all('feedapi_after_settings', $args['nid'], $settings);
}
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;
}
/**
* 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');
$feed->feed_type = "XML feed";
/*
Todo - move assign procedure to 'refresh'. Decide what to do with $feed->feed_type = "XML feed"
$assigned = _feedapi_assign_parser_processor($feed->url, $node_type_settings);
$feed->processors = $assigned['processors'];
$feed->parsers = $assigned['parsers'];
$feed->feed_type = $assigned['type'];
*/
if ($feed->url) {
$feed = _feedapi_call_parsers($feed, $feed->parsers, FALSE);
}
$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' => '