refactor(rss): declare the comments feed from rss_menu's own e_rss.php - #6458
Open
e107help[bot] wants to merge 3 commits into
Open
e107help[bot] wants to merge 3 commits into
e107help[bot] wants to merge 3 commits into
Conversation
The comments feed was the one feed rss_menu served inline, from a switch arm in rss.php, while the resolver held its pre-0.7.6 numeric key 5 and the admin importer seeded its row from a hardcoded block. Every other feed is resolved from what the plugin serving it declares. Commenting is core rather than a plugin, so the feed is declared by rss_menu, which serves every other feed and is installed wherever this feed is reachable. Two things had to widen for existing sites to keep working. The addon scan now reads this plugin's own folder as well as the plugins the e_rss_list pref names. Only e_plugin::buildAddonPrefLists() writes that pref, and nothing runs it on a core upgrade, so a feed that ships with core cannot wait for a plugin scan before it resolves. Ownership of a legacy numeric key now also matches a row whose rss_path is the feed's own key, which is what a row written before the feed became an addon holds. Without that, a request for key 5 would find the row and then hand rssCreate the number, which serves nothing. The importer's duplicate check drops rss_path for the same reason: rss.php serves a feed by url and topic id alone, so a row already holding those is this feed however its path is spelled, and a site that has the feed is not offered it again after the move. Item links come from SITEURL rather than from $_SERVER['HTTP_HOST'], so the feed honours the site's URL configuration instead of whichever name the request happened to arrive under. Refs #5880
The feed read comment_author, a column the 2.0 schema split into comment_author_id and comment_author_name, and then stripped the "id." prefix that column used to carry. On a v2 database that read has always been empty, so every item's author fell away and buildRss emitted no dc:creator element for the feed at all. Read comment_author_name, which is what comment::enter_comment() writes. Refs #5880
Every other item field in the three output modes goes through toRss(). The author did not, in any of them. The comments feed supplied an empty author until the previous commit, so the sink was dead for it, but the news feed has been handing user_name over raw since the mapper existed, and the comment handler writes USERNAME verbatim while toDB leaves an ampersand alone. One commenter called Tom & Jerry therefore makes the whole document malformed XML, and a conforming reader rejects a feed in one piece rather than skipping the item it choked on. Refs #5880
This was referenced Sep 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Fixes #5880.
Every RSS feed a plugin serves is resolved from what that plugin declares: its
e_rss.phpreturns the feed inconfig(), builds it indata(), and names anypre-v0.7.6 numeric key it still answers to in
legacy(). The comments feed wasthe exception.
rss_menuserved it inline from acase 'comments':armin
rssCreate, held its legacy key 5 inrss_resolver.php,and seeded its row from a
hardcoded block in the admin importer.
Three hardcodes for one feed.
Commenting is core rather than a plugin, so there is no
e107_plugins/commentsto put the addon in. Deltik settled the location: it lives in
rss_menu, whichalready serves every other feed, is installed wherever this feed is reachable,
and needs no new folder and no new plugin registration.
What Changed
e107_plugins/rss_menu/e_rss.php, classrss_menu_rss.legacy()returnsarray(5 => 'comments'),config()returns the feed the importer used tohardcode, and
data()is the oldcommentItems()with the five privatemethods behind it moved across.
rss.phploses thecase 'comments':arm and those five methods. The switchthat remains carries only the three 0.7 content types that never became
plugins.
rss_addonsscans this plugin's own folder as well as the plugins thee_rss_listpref names. Onlye_plugin::buildAddonPrefLists()writes that pref, and nothing runs it on a core upgrade, so the feed has to
resolve before an admin has run the plugin update that would.
legacyKeys()loops the same list instead of
e107::getAddonConfig(), and the include bothneed is one private method, because a v1 addon declares its feeds by assigning
to
$eplug_rss_feedat include time.rss_feed_resolverdeclares nothing itself. Ownership of a legacy numeric keynow holds when the row does not name a different plugin, which covers a row
whose
rss_pathis the feed's own key and a row older than that column.rss_path.rss.phpserves a feed by urland topic id alone, so a row already holding those is this feed however its
path is spelled, and a site that has the comments feed is not offered it again
after the move.
SITEURLrather than from$_SERVER['HTTP_HOST'],so the feed honours the site's URL configuration instead of whichever name the
request arrived under.
rss_menu_setup::upgrade_post()points a legacy comments row at the pluginthat now serves it, so the row stops naming a folder that does not exist and
the feed stops paying for the legacy lookup on every request. Resolution does
not depend on it; it retires a fallback rather than enabling anything.
rss_menugoes to 1.4 inplugin.xml, anddefault_install.xmlgainsrss_menuine_rss_listso a fresh install matches what a plugin scan wouldwrite.
Two defects the move surfaced are fixed in commits of their own, so they can be
read, or dropped, separately:
comment_author, a column the 2.0 schemasplit
into
comment_author_idandcomment_author_name, so the author was alwaysempty and no item ever carried a
dc:creator.modes and in the Atom entry. Every other field goes through
toRss(). That wasdead for the comments feed while its author was empty, but the news feed has
been handing
user_nameover unescaped(
rss.php#L745),and one commenter called
Tom & Jerrymakes the whole document malformed XML,which a conforming reader rejects in one piece.
How It Was Tested
The whole unit suite in the project's Docker harness on PHP 8.5 with MariaDB
10.11: 2737 tests, green. New coverage:
e107_tests/tests/unit/plugins/rss_menu/e_rssTest.phpseeds a published,unrestricted news item and a comment on it, then asserts that the item link
comes from
SITEURLwith$_SERVER['HTTP_HOST']set to a host the site is notconfigured for, that the row carries its date under
datestamp(the key thefeed mapper reads), and that the author is named.
RssAddonsTest::testLegacyKeysCarryTheCommentsFeed()holds the scan tocovering this plugin's own folder, which is what an existing site depends on.
RssFeedResolverTestgains the two literal-numeric-row cases,rss_path = 'comments'and no path at all, plus a case proving the resolver resolvesnothing when no addon declares a key. The first of those was verified red
against the unmodified
rss_resolver.phpand green with it.rss_setupTestseeds three rows and holds the upgrade routine to rewriting thetwo that are the comments feed and leaving the third alone.
RssCommentsFeedCestgains an author calledTom & Jerry, and asserts thefeed carries the escaped form and not the raw one. Verified red against the
previous commit's
rss.php.RssCommentsFeedCestandCommentFeedParentClassCestare the backwardscompatibility proof, and every assertion in them predates this branch. They seed
a legacy row with
rss_path => 'comments'and fetch the feed over HTTP; all ofthem pass. I then put a site's
e_rss_listpref back toarray('news' => 'news')by hand, which is the shape an upgraded site has, andran them again: they pass there too. That is the case the folder scan exists for.
Backwards Compatibility
The rendered feed XML is unchanged apart from three deliberate differences: item
links now honour the site's URL configuration rather than the request host, each
item carries a
dc:creatorfor the author that the broken column read had beenswallowing, and an author name containing
&,<or>is escaped in everyfeed rather than emitted raw.
No data migration is required for the feed to keep working. A legacy row keeps
resolving under both
commentsand the old numeric5, whether itsrss_pathsays
comments, says nothing, or names the plugin, and an existing site needs noplugin rescan, because the scan covers this plugin's folder whatever the
e_rss_listpref holds. The upgrade routine rewritesrss_pathon a commentsrow that still says
commentsor nothing, which is tidying rather than repair.One shape does change meaning: a row whose
rss_pathnames a differentplugin now serves that plugin's feed under the comments row's name, where before
the inline arm overrode it. The field is
readonly in the admin UI
and no core version wrote that combination, so it takes a hand-edited row to
reach.
rssCreate,rss_addonsandrss_feed_resolvergain no public method and losenone.
rss_menu_setupgainsupgrade_post(), which the plugin upgrade pathcalls by convention.
AI Model
Claude Opus 5 (claude-opus-5), as e107help.
Checklist