views_rss-8.x-2.x-dev/modules/views_rss_core/views_rss_core.module

modules/views_rss_core/views_rss_core.module
<?php

/**
 * @file
 * Provides core <channel> and <item> elements for Views RSS module.
 */

use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Url;

/**
 * Include file with all preprocess functions.
 */
include_once dirname(__FILE__) . '/views_rss_core.inc';

/**
 * Implements hook_views_rss_namespaces().
 */
function views_rss_core_views_rss_namespaces() {
  $namespaces['atom'] = [
    'prefix' => 'xmlns',
    'uri' => 'http://www.w3.org/2005/Atom',
  ];
  $namespaces['content'] = [
    'prefix' => 'xmlns',
    'uri' => 'http://purl.org/rss/1.0/modules/content/',
  ];
  return $namespaces;
}

/**
 * Implements hook_views_rss_item_elements().
 */
function views_rss_core_views_rss_channel_elements() {
  $elements['title'] = [
    'configurable' => FALSE,
    'preprocess functions' => ['views_rss_core_preprocess_channel_title'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-title',
  ];
  $elements['description'] = [
    'description' => t('Description for this feed. If left blank, the default site mission will be used.'),
    'settings form' => ['#type' => 'textarea', '#rows' => 3],
    'preprocess functions' => [
      'views_rss_rewrite_relative_paths',
    ],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-description',
  ];
  $elements['link'] = [
    'configurable' => FALSE,
    'preprocess functions' => ['views_rss_core_preprocess_channel_link'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-link',
  ];
  $elements['atom:link'] = [
    'configurable' => FALSE,
    'preprocess functions' => ['views_rss_core_preprocess_channel_atom_link'],
    'help' => 'http://www.rssboard.org/rss-profile#namespace-elements-atom-link',
  ];
  $elements['language'] = [
    'preprocess functions' => ['views_rss_core_preprocess_channel_language'],
    'description' => t("The language the channel is written in. This allows aggregators to group all Italian language sites, for example, on a single page. See list of <a href='@w3c_url'>allowable values</a> for this element defined by the W3C. If left empty, it will use current site's language.", [
      '@w3c_url' => Url::fromUri('http://www.w3.org/TR/REC-html40/struct/dirlang.html', ['fragment' => 'langcodes'])->toString(),
    ]),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-language',
  ];
  $elements['category'] = [
    'description' => t('Specify one or more categories that the channel belongs to. Separate multiple items with comma.'),
    'preprocess functions' => ['views_rss_core_preprocess_channel_category'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-category',
  ];
  $elements['image'] = [
    'description' => t('Path to the image to be used as the artwork for your feed, for example <em>sites/default/files/AllAboutEverything.jpg</em>. Allowed image formats are GIF, JPEG or PNG. Maximum image width is 144 pixels, maximum height 400 pixels.'),
    'preprocess functions' => ['views_rss_core_preprocess_channel_image'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-image',
  ];
  $elements['copyright'] = [
    'description' => t('Copyright notice for content in the channel.'),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-copyright',
  ];
  $elements['managingEditor'] = [
    'description' => t('Email address for person responsible for editorial content.'),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-managingeditor',
  ];
  $elements['webMaster'] = [
    'description' => t('Email address for person responsible for technical issues relating to channel.'),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-webmaster',
  ];
  $elements['generator'] = [
    'description' => t('A string indicating the program used to generate the channel.'),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-generator',
  ];
  $elements['docs'] = [
    'description' => t("A URL that points to the documentation for the format used in the RSS file. It's for people who might stumble across an RSS file on a Web server 25 years from now and wonder what it is."),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-docs',
  ];
  $elements['cloud'] = [
    'description' => t("Allows processes to register with a cloud to be notified of updates to the channel, implementing a lightweight publish-subscribe protocol for RSS feeds. Example: <em>soap://rpc.sys.com:80/RPC2#pingMe</em>"),
    'preprocess functions' => ['views_rss_core_preprocess_channel_cloud'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-cloud',
  ];
  $elements['ttl'] = [
    'description' => t("ttl stands for time to live. It's a number of minutes that indicates how long a channel can be cached before refreshing from the source."),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-ttl',
  ];
  $elements['skipHours'] = [
    'description' => t('A hint for aggregators telling them which hours they can skip. The hours must be expressed as an integer representing the number of hours since 00:00:00 GMT. Values from 0 to 23 are permitted, with 0 representing midnight. An hour must not be duplicated.'),
    'preprocess functions' => ['views_rss_core_preprocess_channel_skip'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-skiphours',
  ];
  $elements['skipDays'] = [
    'description' => t('A hint for aggregators telling them which days of the week they can skip (up to seven days).'),
    'preprocess functions' => ['views_rss_core_preprocess_channel_skip'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-skipdays',
  ];
  $elements['pubDate'] = [
    'configurable' => FALSE,
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-pubdate',
  ];
  $elements['lastBuildDate'] = [
    'configurable' => FALSE,
    'preprocess functions' => ['views_rss_core_preprocess_channel_last_build_date'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-lastbuilddate',
  ];
  return $elements;
}

/**
 * Implements hook_views_rss_item_elements().
 */
function views_rss_core_views_rss_item_elements() {
  $elements['title'] = [
    'description' => t('The title of the item. Required by RSS specification.'),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-title',
  ];
  $elements['link'] = [
    'description' => t('The URL of the item. Required by RSS specification.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_link'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-link',
  ];
  $elements['description'] = [
    'description' => t('The item synopsis. Required by RSS specification.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_description',
      'views_rss_rewrite_relative_paths',
    ],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-description',
  ];
  $elements['author'] = [
    'description' => t('Email address of the author of the item. A feed published by an individual should omit this element and use the &lt;managingEditor&gt; or &lt;webMaster&gt; channel elements to provide contact information.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_author'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-author',
  ];
  $elements['category'] = [
    'description' => t('Includes the item in one or more categories.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_category'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-category',
  ];
  $elements['comments'] = [
    'description' => t('URL of a page for comments relating to the item.'),
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-comments',
  ];
  $elements['enclosure'] = [
    'description' => t('Describes a media object that is attached to the item.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_enclosure'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-enclosure',
  ];
  $elements['guid'] = [
    'description' => t('A string that uniquely identifies the item.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_guid'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-guid',
  ];
  $elements['pubDate'] = [
    'description' => t('Indicates when the item was published.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_pubdate'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-pubdate',
  ];
  $elements['source'] = [
    'configurable' => FALSE,
    'description' => t('The RSS channel that the item came from.'),
    'preprocess functions' => ['views_rss_core_preprocess_item_source'],
    'help' => 'http://www.rssboard.org/rss-profile#element-channel-item-source',
  ];
  $elements['content:encoded'] = [
    'description' => t("The &lt;content:encoded&gt; element can be used in conjunction with the &lt;description&gt; element to provide an item's full content along with a shorter summary. Under this approach, the complete text of the item is presented in &lt;content:encoded&gt; and the summary in &lt;description&gt;."),
    'preprocess functions' => [
      'views_rss_rewrite_relative_paths',
    ],
    'cdata' => TRUE,
    'help' => 'http://www.rssboard.org/rss-profile#namespace-elements-content-encoded',
  ];
  return $elements;
}

/**
 * Implements hook_views_rss_date_sources().
 */
function views_rss_core_views_rss_date_sources() {
  $sources['node'] = [
    'lastBuildDate' => [
      'table' => 'node_field_data',
      'field' => 'changed',
    ],
  ];
  $sources['node_revisions'] = [
    'lastBuildDate' => [
      'table' => 'node_field_revision',
      'field' => 'changed',
    ],
  ];
  $sources['comments'] = [
    'lastBuildDate' => [
      'table' => 'comment_field_data',
      'field' => 'changed',
    ],
  ];
  $sources['files'] = [
    'lastBuildDate' => [
      'table' => 'file_managed',
      'field' => 'changed',
    ],
  ];
  $sources['users'] = [
    'lastBuildDate' => [
      'table' => 'users_field_data',
      'field' => 'changed',
    ],
  ];
  return $sources;
}

/**
 * Implements hook_views_query_alter().
 */
function views_rss_core_views_query_alter($view, $query) {
  if ($view->style_plugin->getPluginId() == 'rss_fields') {
    // Use an intermediary variable to avoid strict PHP warnings.
    $base_table_array = $view->getBaseTables();
    $base_table_array = array_keys($base_table_array);
    $base_table = reset($base_table_array);

    $date_sources = views_rss_get('date_sources');
    foreach (array_keys($date_sources) as $module) {
      if (isset($date_sources[$module][$base_table])) {
        // Select the most recent node update date for <lastBuildDate> element.
        if (isset($date_sources[$module][$base_table]['lastBuildDate'])) {
          $query->fields['lastBuildDate'] = $date_sources[$module][$base_table]['lastBuildDate'];
        }
      }
    }
  }
}

/**
 * Implements hook_views_rss_options_form_validate().
 */
function views_rss_core_views_rss_options_form_validate($form, $form_state) {
  $form_state_values = $form_state->getValues();

  // Validate channel <image> element.
  if (!empty($form_state_values['style_options']['channel']['core']['views_rss_core']['image'])) {
    // Do not validate absolute URLs, as this could mean external image.
    if (!UrlHelper::isValid($form_state_values['style_options']['channel']['core']['views_rss_core']['image'], TRUE)) {
      // Check that image exists and is in acceptable format.
      $image = \Drupal::service('image.factory')->get($form_state_values['style_options']['channel']['core']['views_rss_core']['image']);
      if (!$image->isValid()) {
        $form_state->setErrorByName('style_options][channel][core][views_rss_core][image', t('Unable to find %image or incorrect image format.', [
          '%image' => $form_state_values['style_options']['channel']['core']['views_rss_core']['image'],
        ]));
      }
      else {
        // Check image width.
        if ($image->getWidth() > 144) {
          $form_state->setErrorByName('style_options][channel][core][views_rss_core][image', t("Maximum allowed width of an image for feed channel's &lt;image&gt; element is 144 pixels. Specified %image is !width pixels wide.", [
            '%image' => $form_state_values['style_options']['channel']['core']['views_rss_core']['image'],
            '%width' => $image->getWidth(),
          ]));
        }
        // Check image height.
        if ($image->info['height'] > 400) {
          $form_state->setErrorByName('style_options][channel][core][views_rss_core][image', t("Maximum allowed height of an image for feed channel's &lt;image&gt; element is 400 pixels. Specified %image is !height pixels high.", [
            '%image' => $form_state_values['style_options']['channel']['core']['views_rss_core']['image'],
            '%height' => $image->getHeight(),
          ]));
        }
      }
    }
  }

  // Validate channel <docs> element.
  if (!empty($form_state_values['style_options']['channel']['core']['views_rss_core']['docs'])) {
    if (!UrlHelper::isValid($form_state_values['style_options']['channel']['core']['views_rss_core']['docs'], TRUE)) {
      $form_state->setErrorByName('style_options][channel][core][views_rss_core][docs', t("Not a valid URL."));
    }
  }
}

/**
 * Prepares correct variables for RSS feed templates.
 *
 * Drupal core template_preprocess_views_view_rss() forces values of some
 * elements, thus making them not configurable through Views RSS (these are
 * channel 'title', 'description' and 'link' elements). Because we want them
 * all to be configurable through Views RSS' preprocess hooks, they need to be
 * reprocessed here again, after template_preprocess_views_view_rss() has done
 * its mess.
 *
 * @see template_preprocess_views_view_rss()
 */
function views_rss_core_preprocess_views_view_rss(&$variables) {
  $view = $variables['view'];
  $style = $view->style_plugin;

  // Work out the pubDate value based upon the most recent date from each item
  // in the feed.
  if (count($view->result) > 0) {
    $max_pub_date = NULL;
    foreach ($variables['rows'] as $row) {
      if (isset($row['#row']) && is_object($row['#row']) && property_exists($row['#row'], 'elements')) {
        $elements = $row['#row']->elements;
        if (is_array($elements) || is_object($elements)) {
          foreach ($elements as $element) {
            if ($element['key'] === 'pubDate') {
              // This string cannot be parsed if there is a dash present.
              // Unfortunately the default date output format for Drupal
              // includes a dash, so remove it.
              $this_pub_date = (string) $element['value'];
              $this_pub_date = str_replace(' - ', ' ', $this_pub_date);
              $this_pub_date = strtotime($this_pub_date);
              if (!empty($this_pub_date) && (!$max_pub_date || $this_pub_date > $max_pub_date)) {
                $max_pub_date = $this_pub_date;
              }
              break;
            }
          }
        }
        // Ensure that the max value is neither the default NULL value nor a
        // zero which would result in the date showing as January 1st, 1970.
        if (!empty($max_pub_date)) {
          $variables['channel_elements']['pubDate'] = [
            '#type' => 'html_tag',
            '#tag' => 'pubDate',
            // Convert the date value to RFC-822 format.
            '#value' => views_rss_format_date($max_pub_date),
          ];
        }
      }
    }
    // Ensure that the max value is neither the default NULL value nor a zero
    // which would result in the date showing as January 1st, 1970.
    if (!empty($max_pub_date)) {
      $variables['channel_elements']['pubDate'] = [
        '#type' => 'html_tag',
        '#tag' => 'pubDate',
        // Convert the date value to RFC-822 format.
        '#value' => views_rss_format_date($max_pub_date),
      ];
    }
  }

  // Get Views RSS-configured values for channel 'title', 'description'
  // and 'link' values and re-add them to theme variables, at the same time
  // removing them from $style->channel_elements, which would need to be
  // converted to XML again without them.
  foreach ($style->channel_elements as $delta => $channel_element) {
    if (is_array($channel_element) && isset($channel_element['key'])) {
      $key = $channel_element['key'];
      // These 3 elements have the same name as their $variables key.
      if (in_array($key, ['title', 'description', 'link'])) {
        // Assign the value received from Views RSS preprocess function, instead
        // the one added by template_preprocess_views_view_rss().
        $variables[$key] = $channel_element['value'];
        // Also, unset these elements from $style->channel_elements to avoid
        // having them printed out twice in feed's channel element.
        unset($style->channel_elements[$delta]);
      }
      // And then, why would all $variables key names use the same names as RSS
      // elements, right? Let's make one different! Thanks Drupal. Seriously.
      if ($key == 'language') {
        $variables['langcode'] = $channel_element['value'];
        unset($style->channel_elements[$delta]);
      }
    }
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc