views_rss.module 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /**
  3. * @file
  4. * Module providing fields-based views style plugin for RSS feed generation.
  5. */
  6. /**
  7. * Module build version.
  8. */
  9. define('VIEWS_RSS_BUILD', '7.x-2.x-dev-20120416');
  10. /**
  11. * Module installation path.
  12. */
  13. define('VIEWS_RSS_PATH', drupal_get_path('module', 'views_rss'));
  14. /**
  15. * In theory, theme.inc should be automatically loaded from hook_views_plugins()
  16. * implementation in views_rss.views.inc - which usually is the case, apart from
  17. * when "Rescan template files" in view configuration is used, when new template
  18. * files are being detected, but theme.inc for some reason is not loaded, so
  19. * template_preprocess_views_view_views_rss() is not available, and we're getting
  20. * "Array" instead of proper feed data as a result.
  21. */
  22. include_once VIEWS_RSS_PATH . '/theme/theme.inc';
  23. /**
  24. * Implements hook_views_api().
  25. */
  26. function views_rss_views_api() {
  27. return array(
  28. 'api' => 3,
  29. 'path' => VIEWS_RSS_PATH . '/views',
  30. );
  31. }
  32. /**
  33. * Returns an array of item elements defined by other modules
  34. * with hook_views_rss_item_elements() and optionally altered with
  35. * hook_views_rss_item_elements_alter() implementations.
  36. */
  37. function views_rss_get($key, $rebuild = FALSE) {
  38. static $data = array();
  39. if (!isset($data[$key]) || empty($data[$key]) || $rebuild === TRUE) {
  40. $cid = 'views_rss:' . $key;
  41. $cached = cache_get($cid, 'cache_views');
  42. if (is_object($cached) && isset($cached->data) && $rebuild === FALSE) {
  43. $data[$key] = $cached->data;
  44. }
  45. else {
  46. // Fetch item elements provided by other modules. We need to manually call
  47. // each module so that we can know which module a given item came from.
  48. $data[$key] = array();
  49. $hook_name = 'views_rss_' . $key;
  50. foreach (module_implements($hook_name) as $module) {
  51. $module_data = call_user_func($module . '_' . $hook_name);
  52. if (isset($module_data) && is_array($module_data)) {
  53. $data[$key][$module] = $module_data;
  54. }
  55. }
  56. // Add namespaces not defined by any hook_views_rss_namespaces(),
  57. // but used in any of defined <channel> or <item> elements.
  58. // Let's also add "xmlns" prefix by default to such namespaces.
  59. $function = '_views_rss_process_' . $key;
  60. if (function_exists($function)) {
  61. $data[$key] = $function($data[$key]);
  62. }
  63. // Allow other modules to alter obtained item elements.
  64. drupal_alter($hook_name, $data[$key]);
  65. // Store it infinitely in cache (rebuild only on cache clear).
  66. cache_set($cid, $data[$key], 'cache_views');
  67. }
  68. }
  69. return $data[$key];
  70. }
  71. /**
  72. * Add namespaces not defined by any hook_views_rss_namespaces(),
  73. * but used in any of defined <channel> or <item> elements.
  74. * Let's also add "xmlns" prefix by default to such namespaces.
  75. */
  76. function _views_rss_process_namespaces($namespaces) {
  77. foreach (views_rss_get('channel_elements') as $module => $elements) {
  78. foreach (array_keys($elements) as $element) {
  79. list($namespace, $element_name) = views_rss_extract_element_names($element);
  80. if ($namespace && !isset($namespaces[$module][$namespace])) {
  81. $namespaces[$module][$namespace] = array('prefix' => 'xmlns', 'uri' => NULL);
  82. }
  83. }
  84. }
  85. foreach (views_rss_get('item_elements') as $module => $elements) {
  86. foreach (array_keys($elements) as $element) {
  87. list($namespace, $element_name) = views_rss_extract_element_names($element);
  88. if ($namespace && !isset($namespaces[$module][$namespace])) {
  89. $namespaces[$module][$namespace] = array('prefix' => 'xmlns', 'uri' => NULL);
  90. }
  91. }
  92. }
  93. return $namespaces;
  94. }
  95. /**
  96. * Add table aliases for additional fields used for altering view query.
  97. */
  98. function _views_rss_process_date_sources($date_sources) {
  99. foreach ($date_sources as $module => $module_date_sources) {
  100. foreach ($module_date_sources as $base_table => $elements) {
  101. foreach ($elements as $element_name => $definition) {
  102. if (!isset($definition['alias'])) {
  103. $date_sources[$module][$base_table][$element_name]['alias'] = $element_name;
  104. }
  105. }
  106. }
  107. }
  108. return $date_sources;
  109. }
  110. /**
  111. * Extracts and returns an array containing element namespace and name.
  112. */
  113. function views_rss_extract_element_names($element, $core_namespace = '') {
  114. if (!strstr($element, ':')) {
  115. $element = $core_namespace . ':' . $element;
  116. }
  117. return explode(':', $element);
  118. }
  119. /**
  120. * Preprocess callback.
  121. * Replaces relative paths in element values with absolute URLs.
  122. * Based on preg_match from rel_to_abs module by lourenzo,
  123. * with added patch from issue #1335734 by joelstein.
  124. * @see http://drupal.org/project/rel_to_abs
  125. * @see http://drupal.org/node/1335734
  126. */
  127. function views_rss_rewrite_relative_paths(&$variables) {
  128. // Rewriting relative paths should be enabled by default,
  129. // so rewrite relative paths even if option value is not set.
  130. if (
  131. !isset($variables['view']->style_plugin->options['feed_settings']['absolute_paths'])
  132. || !empty($variables['view']->style_plugin->options['feed_settings']['absolute_paths'])
  133. ) {
  134. global $base_path;
  135. foreach ($variables['elements'] as $delta => $element) {
  136. if (isset($element['value'])) {
  137. // Value is an array, so this is a set of subelements.
  138. if (is_array($element['value'])) {
  139. views_rss_rewrite_relative_paths($variables['elements'][$delta]['value']);
  140. }
  141. // Value is a string, so just process it.
  142. else {
  143. $pattern = '/(src|href)=(\'|")[^\/]' . preg_quote($base_path, '/') . '/';
  144. $replacement = '$1=$2' . url('<front>', array('absolute' => TRUE));
  145. $variables['elements'][$delta]['value'] = preg_replace($pattern, $replacement, $element['value']);
  146. }
  147. }
  148. }
  149. }
  150. }
  151. /**
  152. * Forms associative array from linear array,
  153. * or returns original array if already associative.
  154. */
  155. function views_rss_map_assoc($array) {
  156. if (!(array_keys($array) !== range(0, count($array) - 1))) {
  157. $array = drupal_map_assoc($array);
  158. }
  159. return $array;
  160. }