* A PHP-Based RSS and Atom Feed Framework.
* Takes the hard work out of managing a complete RSS/Atom solution.
* Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the SimplePie Team nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific prior
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
* AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue
* @link http://simplepie.org/ SimplePie
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* Manages all item-related data
* Used by {@see \SimplePie\SimplePie::get_item()} and {@see \SimplePie\SimplePie::get_items()}
* This class can be overloaded with {@see \SimplePie\SimplePie::set_item_class()}
* @package \SimplePie\SimplePie
class Item implements RegistryAware
* @var \SimplePie\SimplePie
* @var \SimplePie\Registry
* Create a new item object
* This is usually used by {@see \SimplePie\SimplePie::get_items} and
* {@see \SimplePie\SimplePie::get_item}. Avoid creating this manually.
* @param \SimplePie\SimplePie $feed Parent feed
* @param array $data Raw data
public function __construct($feed, $data)
* Set the registry handler
* This is usually used by {@see \SimplePie\Registry::create}
* @param \SimplePie\Registry $registry
public function set_registry(\SimplePie\Registry $registry)/* : void */
$this->registry = $registry;
* Get a string representation of the item
public function __toString()
return md5(serialize($this->data));
* Remove items that link back to this before destroying this object
public function __destruct()
* Get data for an item-level element
* This method allows you to get access to ANY element/attribute that is a
* sub-element of the item/entry tag.
* See {@see \SimplePie\SimplePie::get_feed_tags()} for a description of the return value
* @see http://simplepie.org/wiki/faq/supported_xml_namespaces
* @param string $namespace The URL of the XML namespace of the elements you're trying to access
* @param string $tag Tag name
public function get_item_tags($namespace, $tag)
if (isset($this->data['child'][$namespace][$tag])) {
return $this->data['child'][$namespace][$tag];
* Get the base URL value.
* Uses `<xml:base>`, or item link, or feed base URL.
public function get_base($element = [])
if (!empty($element['xml_base_explicit']) && isset($element['xml_base'])) {
return $element['xml_base'];
$link = $this->get_permalink();
return $this->feed->get_base($element);
* @see \SimplePie\SimplePie::sanitize()
* @param string $data Data to sanitize
* @param int $type One of the \SimplePie\SimplePie::CONSTRUCT_* constants
* @param string $base Base URL to resolve URLs against
* @return string Sanitized data
public function sanitize($data, $type, $base = '')
return $this->feed->sanitize($data, $type, $base);
* Note: this may not work as you think for multifeeds!
* @link http://simplepie.org/faq/typical_multifeed_gotchas#missing_data_from_feed
* @return \SimplePie\SimplePie
public function get_feed()
* Get the unique identifier for the item
* This is usually used when writing code to check for new items in a feed.
* Uses `<atom:id>`, `<guid>`, `<dc:identifier>` or the `about` attribute
* for RDF. If none of these are supplied (or `$hash` is true), creates an
* MD5 hash based on the permalink, title and content.
* @param boolean $hash Should we force using a hash instead of the supplied ID?
* @param string|false $fn User-supplied function to generate an hash
public function get_id($hash = false, $fn = 'md5')
if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'id')) {
return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'id')) {
return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'guid')) {
return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'identifier')) {
return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'identifier')) {
return $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
} elseif (isset($this->data['attribs'][\SimplePie\SimplePie::NAMESPACE_RDF]['about'])) {
return $this->sanitize($this->data['attribs'][\SimplePie\SimplePie::NAMESPACE_RDF]['about'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
} elseif (!is_callable($fn)) {
trigger_error('User-supplied function $fn must be callable', E_USER_WARNING);
$this->get_permalink().$this->get_title().$this->get_content()
* Get the title of the item
* Uses `<atom:title>`, `<title>` or `<dc:title>`
* @since Beta 2 (previously called `get_item_title` since 0.8)
public function get_title()
if (!isset($this->data['title'])) {
if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'title')) {
$this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$return[0]['attribs']]), $this->get_base($return[0]));
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'title')) {
$this->data['title'] = $this->sanitize($return[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$return[0]['attribs']]), $this->get_base($return[0]));
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'title')) {
$this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'title')) {
$this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'title')) {
$this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'title')) {
$this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
} elseif ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'title')) {
$this->data['title'] = $this->sanitize($return[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
$this->data['title'] = null;
return $this->data['title'];
* Get the content for the item
* Prefers summaries over full content , but will return full content if a
* summary does not exist.
* To prefer full content instead, use {@see get_content}
* Uses `<atom:summary>`, `<description>`, `<dc:description>` or
* @param boolean $description_only Should we avoid falling back to the content?
public function get_description($description_only = false)
if (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'summary')) &&
($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_10_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'summary')) &&
($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10, 'description')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_MAYBE_HTML, $this->get_base($tags[0])))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, 'description')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($tags[0])))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, 'description')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, 'description')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'summary')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($tags[0])))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ITUNES, 'subtitle')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_090, 'description')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML))) {
} elseif (!$description_only) {
return $this->get_content(true);
* Get the content for the item
* Prefers full content over summaries, but will return a summary if full
* content does not exist.
* To prefer summaries instead, use {@see get_description}
* Uses `<atom:content>` or `<content:encoded>` (RSS 1.0 Content Module)
* @param boolean $content_only Should we avoid falling back to the description?
public function get_content($content_only = false)
if (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, 'content')) &&
($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_10_content_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_03, 'content')) &&
($return = $this->sanitize($tags[0]['data'], $this->registry->call(Misc::class, 'atom_03_construct_type', [$tags[0]['attribs']]), $this->get_base($tags[0])))) {
} elseif (($tags = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded')) &&
($return = $this->sanitize($tags[0]['data'], \SimplePie\SimplePie::CONSTRUCT_HTML, $this->get_base($tags[0])))) {
} elseif (!$content_only) {
return $this->get_description(true);
* Get the media:thumbnail of the item
* Uses `<media:thumbnail>`
public function get_thumbnail()
if (!isset($this->data['thumbnail'])) {
if ($return = $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_MEDIARSS, 'thumbnail')) {
$thumbnail = $return[0]['attribs'][''];
if (empty($thumbnail['url'])) {
$this->data['thumbnail'] = null;
$thumbnail['url'] = $this->sanitize($thumbnail['url'], \SimplePie\SimplePie::CONSTRUCT_IRI, $this->get_base($return[0]));
$this->data['thumbnail'] = $thumbnail;
$this->data['thumbnail'] = null;
return $this->data['thumbnail'];
* Get a category for the item
* @since Beta 3 (previously called `get_categories()` since Beta 2)
* @param int $key The category that you want to return. Remember that arrays begin with 0, not 1
* @return \SimplePie\Category|null
public function get_category($key = 0)
$categories = $this->get_categories();
if (isset($categories[$key])) {
return $categories[$key];
* Get all categories for the item
* Uses `<atom:category>`, `<category>` or `<dc:subject>`
* @return \SimplePie\Category[]|null List of {@see \SimplePie\Category} objects
public function get_categories()
foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_ATOM_10, $type) as $category) {
if (isset($category['attribs']['']['term'])) {
$term = $this->sanitize($category['attribs']['']['term'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
if (isset($category['attribs']['']['scheme'])) {
$scheme = $this->sanitize($category['attribs']['']['scheme'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
if (isset($category['attribs']['']['label'])) {
$label = $this->sanitize($category['attribs']['']['label'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
$categories[] = $this->registry->create(Category::class, [$term, $scheme, $label, $type]);
foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_RSS_20, $type) as $category) {
// This is really the label, but keep this as the term also for BC.
// Label will also work on retrieving because that falls back to term.
$term = $this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
if (isset($category['attribs']['']['domain'])) {
$scheme = $this->sanitize($category['attribs']['']['domain'], \SimplePie\SimplePie::CONSTRUCT_TEXT);
$categories[] = $this->registry->create(Category::class, [$term, $scheme, null, $type]);
foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_11, $type) as $category) {
$categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null, $type]);
foreach ((array) $this->get_item_tags(\SimplePie\SimplePie::NAMESPACE_DC_10, $type) as $category) {
$categories[] = $this->registry->create(Category::class, [$this->sanitize($category['data'], \SimplePie\SimplePie::CONSTRUCT_TEXT), null, null, $type]);
if (!empty($categories)) {
return array_unique($categories);
* Get an author for the item
* @param int $key The author that you want to return. Remember that arrays begin with 0, not 1
* @return \SimplePie\Author|null
public function get_author($key = 0)
$authors = $this->get_authors();
if (isset($authors[$key])) {
* Get a contributor for the item
* @param int $key The contrbutor that you want to return. Remember that arrays begin with 0, not 1
* @return \SimplePie\Author|null
public function get_contributor($key = 0)
$contributors = $this->get_contributors();
if (isset($contributors[$key])) {
return $contributors[$key];
* Get all contributors for the item
* Uses `<atom:contributor>`
* @return \SimplePie\Author[]|null List of {@see \SimplePie\Author} objects
public function get_contributors()