There are a couple of things I don’t like with the feeds produced by the standard Grav Syndication Feed Plugin. Fortunately, the feeds are generated via Twig templates that can easily be customized!

Issue

I’ve setup my blog so that each page starts with a summary section that ends with ===. Check your Grav Configuration > Site > Page Summary to confirm it is enabled. If you do not have a summary section, then best you stop reading!

Anyway, I don’t like that the plugin generates feeds that comprise:

  1. A fixed number of characters from the blog page (the “Feed Length” configuration in the screenshot below) - I would rather the feed contain just the summary.
  2. Images - I would rather not have images or links to images in the feed! Alas, there is no configuration to change this behaviour.

The Feed Plugin configuration: Grav Feed Plugin Configuration

Fix

As mentioned, changing the feed output is simply overriding three Twig templates in the folder user/plugins/feed/templates:

  • feed.atom.twig
  • feed.json.twig
  • feed.rss.twig

To override these files, copy them to your active theme’s templates folder folder, and then edit each file to:

  1. Replace item.content with item.summary.
  2. Comment out or delete lines pertaining to the banner and image variables.

BTW, I also implemened a “Read more...” link - this is easy and I leave this as an excertise for the reader!

For feed.rss.twig and, similarly, feed.rss.twig, edit the [CDATA[...]] section:

{% set collection = collection|default(page.collection) %}
{% set lastBuildDate = 0 %}
{% for page in collection %}
    {%- set lastBuildDate = max(lastBuildDate, page.date) %}
    {%- if collection.params.show_last_modified %}
        {%- set lastBuildDate = max(feed_updated, page.modified) %}
    {%- endif %}
{% endfor %}
<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>{{ collection.params.title }}</title>
        <link>{{ page.url(true) }}</link>
        <atom:link href="{{ uri.rootUrl(true)~uri.uri() }}" rel="self" type="application/rss+xml"/>
        <description>{{ collection.params.description }}</description>
        <language>{{ grav.language.getLanguage|default(config.system.language.default_lang)|default('en') }}</language>
        <lastBuildDate>{{ lastBuildDate|date('D, d M Y H:i:s O') }}</lastBuildDate>
        {% for item in collection %}
        {% set banner = item.media.images|first %}
        <item>
            <title>{{ item.title|e }}</title>
            <link>{{ item.url(true) }}</link>
            <guid>{{ item.url(true) }}</guid>
            <pubDate>{{ item.date|date('D, d M Y H:i:s O') }}</pubDate>
            <description>
                <![CDATA[
{#
                {% if banner %}
                {{ banner.cropZoom(1200,800).html|absolute_url|raw }}
                {% endif %}
                {{ item.content|safe_truncate_html(collection.params.length)|raw }}
#}
                {{ item.summary|safe_truncate_html(collection.params.length)|raw }}
                ]]>
            </description>
            {% for tag in item.taxonomy.tag %}
                <category>{{ tag|e }}</category>
            {% endfor %}
        </item>
        {% endfor %}
    </channel>
</rss>

While for feed.json.twig, edit the"content_html": item.content line and the set image section. I noticed the current version of the plugin does not use the banner variable, so feel free to comment it out as well:

{# Format specification: https://www.jsonfeed.org/version/1/ #}
{% set collection = collection|default(page.collection) %}
{% set jsonfeed = {
    "version" : "https://jsonfeed.org/version/1",
    "title": collection.params.title,
    "home_page_url": page.url(true),
    "feed_url": uri.rootUrl(true)~uri.uri(),
    "description": collection.params.description,
    "author": {"name": site.author.name}
} %}

{% set itemList = [] %}
{% for item in collection %}
    {%- set post = {
        "title": item.title|e,
        "date_published": item.date|date('Y-m-d\\TH:i:sP'),
        "id": item.url(true),
        "url": item.url(true),
        "content_html": item.summary|safe_truncate_html(collection.params.length)
    } %}
{#
    {% set banner = item.media.images|first %}
#}
    {% if item.header.metadata.description %}
        {%- set post = post|merge({"summary": item.header.metadata.description|e}) %}
    {% endif %}

    {% if collection.params.show_last_modified %}
        {%- set post = post|merge({"date_modified": item.modified|date('Y-m-d\\TH:i:sP')}) %}
    {% endif %}

    {% if item.taxonomy.tag %}
        {%- set post = post|merge({"tags": item.taxonomy.tag}) %}
    {% endif %}
{#
    {% set image = item.media.images|first %}
    {% if image %}
        {%- set post = post|merge({"image": image.url(true)}) %}
    {% endif %}
#}
    {%- set itemList = itemList|merge([post]) %}
{% endfor %}

{% set jsonfeed = jsonfeed|merge({"items": itemList}) %}
{{- jsonfeed|json_encode|raw }}

It’s a good idea validate the feeds produced, for example, using the W3C Feed Validation Service and JSON Linter.

This method will work if you would like to make other changes to the feed template.