views_rss-8.x-2.x-dev/views_rss.module
views_rss.module
<?php
/**
* @file
* Module providing fields-based views style plugin for RSS feed generation.
*/
use Drupal\Core\Url;
/**
* Get a list of elements from other modules.
*
* @return array
* Item elements defined by other modules.
*/
function views_rss_get($key, $rebuild = FALSE) {
static $data = [];
if (!isset($data[$key]) || empty($data[$key]) || $rebuild === TRUE) {
$cid = 'views_rss:' . $key;
$cache = \Drupal::cache('data')->get($cid);
if (isset($cache->data) && $rebuild === FALSE) {
$data[$key] = $cache->data;
}
else {
// Fetch item elements provided by other modules. We need to manually call
// each module so that we can know which module a given item came from.
$data[$key] = [];
$hook_name = 'views_rss_' . $key;
$modules = [];
\Drupal::moduleHandler()->invokeAllWith($hook_name, function (callable $hook_name, string $module) use (&$modules) {
$modules[] = $module;
});
foreach ($modules as $module) {
$module_data = \Drupal::moduleHandler()->invoke($module, $hook_name);
if (isset($module_data) && is_array($module_data)) {
$data[$key][$module] = $module_data;
}
}
// Add namespaces not defined by any hook_views_rss_namespaces(),
// but used in any of defined <channel> or <item> elements.
// Let's also add "xmlns" prefix by default to such namespaces.
$function = '_views_rss_process_' . $key;
if (function_exists($function)) {
$data[$key] = $function($data[$key]);
}
// Allow other modules to alter obtained item elements.
\Drupal::moduleHandler()->alter($hook_name, $data[$key]);
// Store it infinitely in cache (rebuild only on cache clear).
\Drupal::cache('data')->set($cid, $data[$key]);
}
}
return $data[$key];
}
/**
* Add namespaces not defined by any hook_views_rss_namespaces().
*
* But used in any of defined <channel> or <item> elements. Also adds "xmlns"
* prefix by default to such namespaces.
*
* @return array
* A list of namespaces to add.
*/
function _views_rss_process_namespaces($namespaces) {
foreach (views_rss_get('channel_elements') as $module => $elements) {
foreach (array_keys($elements) as $element) {
// To use $element_name use the following definition instead:
// @code
// [$namespace, $element_name]
// @endcode
[$namespace] = views_rss_extract_element_names($element);
if ($namespace && !isset($namespaces[$module][$namespace])) {
$namespaces[$module][$namespace] = ['prefix' => 'xmlns', 'uri' => NULL];
}
}
}
foreach (views_rss_get('item_elements') as $module => $elements) {
foreach (array_keys($elements) as $element) {
// To use $element_name use the following definition instead:
// @code
// [$namespace, $element_name]
// @endcode
[$namespace] = views_rss_extract_element_names($element);
if ($namespace && !isset($namespaces[$module][$namespace])) {
$namespaces[$module][$namespace] = ['prefix' => 'xmlns', 'uri' => NULL];
}
}
}
return $namespaces;
}
/**
* Add table aliases for additional fields used for altering view query.
*
* @return array
* The data sources, with table aliases added.
*/
function _views_rss_process_date_sources($date_sources) {
foreach ($date_sources as $module => $module_date_sources) {
foreach ($module_date_sources as $base_table => $elements) {
foreach ($elements as $element_name => $definition) {
if (!isset($definition['alias'])) {
$date_sources[$module][$base_table][$element_name]['alias'] = $element_name;
}
}
}
}
return $date_sources;
}
/**
* Extracts and returns an array containing element namespace and name.
*/
function views_rss_extract_element_names($element, $core_namespace = '') {
if (!strstr($element, ':')) {
$element = $core_namespace . ':' . $element;
}
return explode(':', $element);
}
/**
* Element preprocess callback: replaces relative paths with absolute URLs.
*
* Based on preg_match from rel_to_abs module by lourenzo, with added patch from
* issue #1335734 by joelstein.
*
* @see http://drupal.org/project/rel_to_abs
* @see http://drupal.org/node/1335734
*/
function views_rss_rewrite_relative_paths(&$variables) {
// Rewriting relative paths should be enabled by default,
// so rewrite relative paths even if option value is not set.
if (
!isset($variables['view']->style_plugin->options['feed_settings']['absolute_paths'])
|| !empty($variables['view']->style_plugin->options['feed_settings']['absolute_paths'])
) {
global $base_path;
foreach ($variables['elements'] as $delta => $element) {
if (isset($element['value'])) {
// Value is an array, so this is a set of subelements.
if (is_array($element['value'])) {
views_rss_rewrite_relative_paths($variables['elements'][$delta]['value']);
}
// Value is a string, so just process it.
else {
$pattern = '/(data-src|srcset|src|href)=(\'|")' . preg_quote($base_path, '/') . '(?!\/)/';
$replacement = '$1=$2' . $GLOBALS['base_url'] . '/';
$variables['elements'][$delta]['value'] = preg_replace($pattern, $replacement, $element['value']);
}
}
}
}
}
/**
* Maps associative arrays.
*
* Forms associative array from linear array, or returns original array if
* already associative.
*/
function views_rss_map_assoc($array) {
if (!(array_keys($array) !== range(0, count($array) - 1))) {
$array = array_combine($array, $array);
}
return $array;
}
/**
* Implements hook_theme_registry_alter().
*/
function views_rss_theme_registry_alter(array &$registry) {
$module_dir = \Drupal::service('extension.list.module')->getPath('views_rss');
// Use the twig file that comes with this module so that the CDATA wrapper can
// be added.
$registry['views_view_row_rss']['path'] = $module_dir . '/templates';
// Use the custom twig file for the main RSS output to work around problems
// outputting a LINK tag in Twig.
$registry['views_view_rss']['path'] = $module_dir . '/templates';
}
/**
* Simplified function for obtaining the homepage's URL.
*
* @return string
* The URL for the homepage.
*/
function views_rss_link_to_front_page() {
static $url;
if (empty($url)) {
$url = Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString();
}
return $url;
}
/**
* Output a timestamp in the format required for RSS.
*
* @param int $timestamp
* A timestamp value.
*
* @return string
* The timestamp value in the required format.
*/
function views_rss_format_date($timestamp) {
return date(\DateTimeInterface::RFC822, $timestamp);
}
