PhoenixKit.Modules.Publishing.Web.Controller.Listing (PhoenixKitPublishing v0.4.6)

Copy Markdown View Source

Group listing functionality for the publishing controller.

Handles rendering post listings with:

  • Language filtering and fallback
  • Pagination
  • Translation link building for listings

Summary

Functions

The group's published posts for the requested language, title/excerpt-resolved and sorted newest-first — the shared source for the RSS feed and the post page's prev/next navigation. Deliberately independent of the group's listing_sort: feeds and chronological neighbors always mean "newest first".

Fetches group configuration by slug.

Filter posts to only include those that have matching language content. Handles both exact matches and base code matches (e.g., "en" matches "en-US"). Translation visibility is based on existence only — status comes from the post level.

Strict version - only matches exact language, no fallback to base code.

Filters posts to only include published ones. Excludes timestamp-mode posts with a future post_date.

Find a matching language in available languages. Handles exact matches and base code matching.

Get the actual language that the fallback matched. Used to redirect to the correct URL when requested language has no content.

Gets the page number from params.

Gets the posts per page setting.

The chronological neighbors of a post within its group + language, as %{newer:, older:, date_counts:} — either neighbor nil at the chronology's edge (or when the post isn't in the published set, e.g. a draft preview). date_counts covers the WHOLE published set, so a timestamp neighbor's URL correctly includes its time segment when the date has same-day siblings.

Paginates a list of posts.

Renders the group index page with resolved posts.

Renders the group listing as SEARCH RESULTS for query. Falls back to the normal listing when the group's search_enabled setting is off — a ?q= on a search-disabled group is ignored, not an error. The :ok shape matches render_group_index/3 plus :search_query, with the Featured/Latest bands suppressed and a single results page (capped at 50 matches, newest first).

Renders a category/tag archive: the listing shape (render_group_index/3 fields) with the term's posts, the bands suppressed, and a :term_filter map (%{type:, label:, count:}) for the heading. Single results page, newest first, capped like search.

Resolves posts for the requested language, handling exact match vs fallback.

chronological_posts/3 narrowed to a term scope: nil (whole group), {:category, slug} (the category AND its descendants — WordPress archive rule), or {:tag, tag} (case-insensitive tag match). Returns {:ok, posts, label} where label is the category's translated name (nil for the whole group, the raw tag for tags), or {:error, :not_found} for an unknown category / a tag no published post carries.

Search matches for a group's public listing: a DB substring pass (title + body of active PUBLISHED versions, candidate languages, ILIKE-escaped) intersected with the chronological cache maps — so results carry the same resolved titles/URLs/order as the listing. Returns {posts, date_counts}, the counts computed over the WHOLE published set so a matched timestamp post's URL keeps its time segment when non-matched same-day siblings exist.

Functions

chronological_posts(group_slug, language, limit \\ nil)

The group's published posts for the requested language, title/excerpt-resolved and sorted newest-first — the shared source for the RSS feed and the post page's prev/next navigation. Deliberately independent of the group's listing_sort: feeds and chronological neighbors always mean "newest first".

fetch_group(group_slug)

Fetches group configuration by slug.

filter_by_exact_language(posts, group_slug, language)

Filter posts to only include those that have matching language content. Handles both exact matches and base code matches (e.g., "en" matches "en-US"). Translation visibility is based on existence only — status comes from the post level.

filter_by_exact_language_strict(posts, language)

Strict version - only matches exact language, no fallback to base code.

filter_published(posts)

Filters posts to only include published ones. Excludes timestamp-mode posts with a future post_date.

find_matching_language(language, available_languages)

Find a matching language in available languages. Handles exact matches and base code matching.

get_fallback_language(requested_language, posts)

Get the actual language that the fallback matched. Used to redirect to the correct URL when requested language has no content.

get_page_param(params)

Gets the page number from params.

get_per_page_setting()

Gets the posts per page setting.

neighbor_posts(group_slug, language, post_uuid)

The chronological neighbors of a post within its group + language, as %{newer:, older:, date_counts:} — either neighbor nil at the chronology's edge (or when the post isn't in the published set, e.g. a draft preview). date_counts covers the WHOLE published set, so a timestamp neighbor's URL correctly includes its time segment when the date has same-day siblings.

paginate(posts, page, per_page)

Paginates a list of posts.

render_group_index(conn, ctx, all_posts)

Renders the group index page with resolved posts.

render_group_listing(conn, group_slug, language, params)

Renders a group listing page.

render_search_results(conn, group_slug, language, query, params)

Renders the group listing as SEARCH RESULTS for query. Falls back to the normal listing when the group's search_enabled setting is off — a ?q= on a search-disabled group is ignored, not an error. The :ok shape matches render_group_index/3 plus :search_query, with the Featured/Latest bands suppressed and a single results page (capped at 50 matches, newest first).

render_term_archive(conn, group_slug, language, term)

Renders a category/tag archive: the listing shape (render_group_index/3 fields) with the term's posts, the bands suppressed, and a :term_filter map (%{type:, label:, count:}) for the heading. Single results page, newest first, capped like search.

resolve_listing_posts_for_language(conn, ctx)

Resolves posts for the requested language, handling exact match vs fallback.

scoped_chronological_posts(group_slug, language, arg3)

chronological_posts/3 narrowed to a term scope: nil (whole group), {:category, slug} (the category AND its descendants — WordPress archive rule), or {:tag, tag} (case-insensitive tag match). Returns {:ok, posts, label} where label is the category's translated name (nil for the whole group, the raw tag for tags), or {:error, :not_found} for an unknown category / a tag no published post carries.

search_posts(group_slug, language, query)

Search matches for a group's public listing: a DB substring pass (title + body of active PUBLISHED versions, candidate languages, ILIKE-escaped) intersected with the chronological cache maps — so results carry the same resolved titles/URLs/order as the listing. Returns {posts, date_counts}, the counts computed over the WHOLE published set so a matched timestamp post's URL keeps its time segment when non-matched same-day siblings exist.