API / Minn\Front

Minn\Front

URL resolution, permalinks, feeds, sitemaps and the public page. 44 classes, 165 public methods and 105 internals. This page is the public surface; each class name opens the whole class.

AdminBar final readonly class

public/minn/src/Minn/Front/AdminBar.php · 326 lines · Open the class →

The Minn bar on the public site: the same server-rendered chrome the app ships (assets/js/bar.js and assets/css/bar.css from the bundle), built here for a signed-in reader who can edit. There is no other bar and no other admin on the engine, so it is on for everyone who passes the edit_posts gate; the app's per-person opt-in does not apply.

ArchiveAddresses final readonly class

public/minn/src/Minn/Front/ArchiveAddresses.php · 97 lines · Open the class →

The archives an address may stand for, as the reference answers them: the front, a search, a term's (a category's, a tag's, a plugin taxonomy's), an author's and a date's. Each is the archive when what it names exists (a term by its path's last slug, a valid date; an author's for any name); whether its page has posts is the main query's to say, and an empty page past the first, or an empty date, is the 404 it decides (Theme\FrontLifecycle::handle404).

new__construct(Minn\Db $db, Minn\Content\Posts $posts, Minn\Content\Terms $terms, Minn\Front\Permalinks $permalinks, Closure $readable)
@param Closure(PostRecord): bool $readable whether the reader may read a post
methodsearch(string $term, int $paged): Minn\Front\Resolution

A search's results page.

methodhome(int $paged): Minn\Front\Resolution

The front: the static front page when there is one, else the posts listing.

methodtaxonomy(string $taxonomy, array $slugs, int $paged): Minn\Front\Resolution

A plugin taxonomy's term archive by its path; a 404 when no term is at that path.

@param list<string> $slugs
methodterm(string $taxonomy, array $slugs, int $paged): Minn\Front\Resolution

A category's or tag's archive by its path; a 404 when no term is at that path. @param list<string> $slugs

@param list<string> $slugs
methodauthor(string $name, int $paged): Minn\Front\Resolution

An author's archive by nicename: the archive for any name, the author's when one has it.

methoddate(array $segments, int $paged): Minn\Front\Resolution

A date archive by year, month and day; a 404 when the date is not one. @param list<string> $segments

@param list<string> $segments
staticisDate(int $year, ?int $month, ?int $day): bool

Whether a year, month and day (the last two optional, a day only with its month) name a date.

insideat()

Archives final readonly class

public/minn/src/Minn/Front/Archives.php · 63 lines · Open the class →

The archive periods wp_get_archives lists: months, years, days and weeks that hold a published post of a type, newest first, each with its post count and archive URL, plus the post-by-post and alphabetical listings. Labels come from the caller's date formatter so the site's locale and week start apply; the week label joins the week's first and last day.

new__construct(Minn\Content\Posts $posts, Closure $date, Closure $dateLink, Closure $week)
@param Closure(string, string): string $date formats a MySQL datetime with a PHP date format
@param Closure(int, ?int, ?int): string $dateLink the year, month, or day archive URL
@param Closure(string): array{start: int, end: int} $week the week's first and last second around a datetime
methodperiods(string $granularity, string $type, string $order, int $limit, Closure $weekLink, string $where = '', string $join = ''): array

The periods of one granularity: monthly, yearly, daily, or weekly; a WHERE and JOIN given are the query's (Posts::archiveBuckets).

@return list<array{period: array{year: int, month: int, day: int, week: int}, url: string, text: string, count: int}>
methodposts(string $type, string $orderBy, string $order, int $limit, Closure $title, Closure $link, string $where = '', string $join = ''): array

The posts themselves, by date or by title.

@param Closure(int, string): string $title the post's title as displayed (or its id when empty)
@param Closure(int): string $link
@return list<array{url: string, text: string, count: int, id: int}>
insideweekPeriod()

AssetsController final readonly class

public/minn/src/Minn/Front/AssetsController.php · 42 lines · Open the class →

The engine's own static assets, served under a reserved path.

new__construct(string $assetsDir)
methodasset(Minn\Http\Request $request, string $path): Minn\Http\ResponseGET /minn/assets/{path*} (public)

One engine asset file.

methodembedScript(Minn\Http\Request $request, string $file): Minn\Http\ResponseGET /wp-includes/js/{file:wp-embed(?:-template)?\.min\.js} (public)

The engine's embed scripts at the addresses the reference serves its own from.

methodjquery(Minn\Http\Request $request, string $file): Minn\Http\ResponseGET /wp-includes/js/jquery/{file:[a-z0-9.-]+\.js} (public)

The MIT libraries the engine ships, served at the paths the reference registers them under.

AttachmentAddresses final readonly class

public/minn/src/Minn/Front/AttachmentAddresses.php · 80 lines · Open the class →

The addresses an attachment's page answers to besides those its rules find (Front\RuleTable: a loose one by its slug at the top, any by its slug under another address, "attachment/" between or not): by id or slug in the query (?attachment_id=, ?attachment=), and as a post (?p=, ?page_id=), which moves to its own page. With attachment pages off (wp_attachment_pages_enabled, the default) every address moves to the file itself; with them on, one that is not its own moves to its page. An attachment is readable as its parent is.

new__construct(Minn\Db $db, Minn\Content\Posts $posts, Minn\Front\Permalinks $permalinks, Closure $readable)
staticnames(Minn\Front\Resolution $resolution): bool

Whether a resolution is an attachment's page.

methodfromQuery(Minn\Http\Request $request, Minn\Front\Redirects $redirects): ?Minn\Front\Resolution

?attachment_id= or ?attachment=: the attachment's page, or a 404; null when the request names neither.

methodasPost(Minn\Content\PostRecord $post, Minn\Http\Request $request, string $key, Minn\Front\Redirects $redirects): ?Minn\Front\Resolution

An attachment asked for as a post (?p=, ?page_id=): it moves to its own page whatever the setting; null for any other post.

methodanswer(Minn\Front\Resolution $resolution, Minn\Http\Request $request, Minn\Front\Redirects $redirects): Minn\Front\Resolution

With attachment pages off (the default), a move to the file itself, from every address, its embed and feed among them: the query along, though an ?attachment_id= address leaves its id behind unless it asked for an embed. With them on, the page as typed, or (the address not its own) a move to its own: the other query arguments along, ?attachment= among them; an embed stays where it was asked for.

insidereadable()

Calendar final readonly class

public/minn/src/Minn/Front/Calendar.php · 99 lines · Open the class →

One month as the calendar widget and block draw it: a table whose caption names the month, whose head lists the week from the site's first day, and whose cells link the days a post was published on to that day's archive; today's cell carries the id the stylesheet lights; the nav below links the nearest months with posts on either side. Markup, whitespace and the attribute order of the two padding cells follow the reference byte for byte, since themes style the table by those hooks.

new__construct(int $year, int $month, int $weekStart, Minn\Front\CalendarLabels $labels, Closure $link)
@param Closure(int, int, ?int): string $link the month archive URL, or the day's when a day is given
methodrender(array $postDays, ?array $previous, ?array $next, ?array $today): string

The table and its navigation.

@param list<int> $postDays days of the month with a published post
@param array{int, int}|null $previous the nearest earlier month with posts, as [year, month]
@param array{int, int}|null $next the nearest later month with posts
@param array{int, int, int}|null $today the site's current date, as [year, month, day]
insidetable(), head(), cell(), navigation(), abbreviation()

CalendarLabels final readonly class

public/minn/src/Minn/Front/CalendarLabels.php · 44 lines · Open the class →

The words a calendar prints: weekday names Sunday first, the short form each column shows (an initial or an abbreviation), month names by number, and the abbreviation the month navigation uses.

new__construct(array $weekdays, array $weekdayShort, array $months, array $monthAbbrev)
@param array<int, string> $weekdays Sunday first
@param array<string, string> $weekdayShort full weekday name to the column heading
@param array<int, string> $months 1 to 12
@param array<string, string> $monthAbbrev full month name to its abbreviation
propreadonly array $weekdays
propreadonly array $weekdayShort
propreadonly array $months
propreadonly array $monthAbbrev
staticenglish(): self

The English tables, with weekday initials as the reference shows by default.

staticenglishAbbreviated(): self

The English tables with three-letter weekday abbreviations.

insidefromEnglish()

Canonical final class

public/minn/src/Minn/Front/Canonical.php · 28 lines · Open the class →

Where a URL should redirect to, by the engine's own resolution: the canonical form of a request (trailing slash, `?p=` to permalink, doubled slashes, former slugs). The front controller applies this before any plugin runs; the `redirect_canonical()` facade asks it again for a URL a plugin names.

staticlocation(Minn\Db $db, Minn\Http\Request $current, ?string $url): ?string

The canonical URL of a request, or null when it already is one.

insiderequestFor()

CommentPostController final readonly class

public/minn/src/Minn/Front/CommentPostController.php · 52 lines · Open the class →

wp-comments-post.php: the comment form's target. The reference's answers, captured: 302 to the comment's anchor (with unapproved and moderation-hash when held), plain pages with 200 for a missing field, 403 when comments are closed, 409 for a duplicate, 429 for posting too quickly, and 405 for anything but POST.

methodpost(Minn\Http\Request $request): Minn\Http\Response* /wp-comments-post.php (public)

The comment form's target.

insidesubmit(), refusal()

EmbedCard final class

public/minn/src/Minn/Front/EmbedCard.php · 95 lines · Open the class →

The parts of a post's embed card the reference's embed template prints, as markup: the featured image and its shape (the widest of the image's sizes; wide enough and it sits above the title, else beside it, both by filter), the site's name and icon, the comments and sharing buttons, and the sharing dialog (its ids the post's and a random number, as on the reference). The facade's template tags print them.

staticthumbnail(): ?array

The featured image the card shows: [attachment id, size, shape], or null. A post's thumbnail, or an image attachment itself, through embed_thumbnail_id, embed_thumbnail_image_size and embed_thumbnail_image_shape.

@return array{0: int, 1: string, 2: string}|null
staticfeaturedImage(?array $thumbnail, string $shape): string

The featured image's block, when the card shows one of this shape.

staticsiteTitle(): string

The site's name and icon, linking home, the whole block through embed_site_title_html.

staticcommentsButton(): string

The comments button: the count, linking to the comments; none on a 404, or with neither comments nor comments open.

staticsharingButton(): string

The button that opens the sharing dialog; none on a 404.

staticsharingDialog(): string

The sharing dialog: the post's address and its embed code, each a tab; none on a 404.

FeedController final readonly class

public/minn/src/Minn/Front/FeedController.php · 60 lines · Open the class →

The feeds, wherever a request asks for one: the feed var of the rule its address matched (the site's at /feed/, the comments' at /comments/feed/, a post's or an archive's after its address, a plugin's own) or ?feed= on any page. Each is WordPress's feed lifecycle: the main query with the feed asked for, then do_feed, whose handler prints the feed and its content type. A feed of something the address names but the site does not have is an empty feed, as the reference serves it.

new__construct(Minn\Content\Site $site)
staticasked(Minn\Http\Request $request, Minn\Front\Resolution $resolution): bool

Whether a request asks for a feed of what it resolved to (the query form only of something that exists).

methodserve(Minn\Http\Request $request, Minn\Front\Resolution $resolution): Minn\Http\Response

The feed a request asks for, of what its address resolved to.

insideserved(), perFeed()

FeedTags final class

public/minn/src/Minn/Front/FeedTags.php · 137 lines · Open the class →

The template tags a feed is written with that take more than a line, as the reference answers them in a feed's loop (probe feed-tags): a post's categories and tags in each feed's markup, its enclosures for RSS and Atom, the link to its comments feed, the feed's build date, and the site icon a feed carries.

staticcategories(string $type): string

A post's category and tag names (each once) in a feed type's markup, before the_category_rss.

staticrssEnclosures(): string

The current post's enclosures as RSS has them: address, length, and the type the third line starts with.

staticatomEnclosures(): string

The current post's enclosures as Atom links: the length a line that is a number, the type a line that is a known MIME type.

staticpostCommentsFeedLink(int $postId, string $feed): string

The address of a post's comments feed in a feed type (the default one bare), through post_comments_feed_link.

staticbuildDate(string $format): string

When the feed last changed, in a format: the newest of its posts' modifications (and comments, for a comments feed); once the loop has run out, the site's last modification; failing both, now.

staticrss2Icon(): string

The site icon as an RSS 2.0 image (titled with the feed's title), or '' without one.

staticatomIcon(): string

The site icon as an Atom icon, or '' without one.

insideenclosures()

FeedTemplates final class

public/minn/src/Minn/Front/FeedTemplates.php · 295 lines · Open the class →

The feed templates do_feed_* loads, written from the reference's output (suite feed-hooks, probes feed-templates): RSS 2.0, Atom, RDF and RSS 0.92 for posts, RSS 2.0 and Atom for comments. Each is written through the template tags, so every feed filter has its say, and fires each feed action where the reference fires it; the whitespace between is the reference's. A template is written once a request, as require_once loads it, and sends its content type through the header callback first.

staticload(string $name, Closure $send): string

A feed template by its name (rss2, rss2-comments, atom, atom-comments, rdf, rss), between wp_before_load_template and wp_after_load_template.

@param Closure(string): void $send sends a header line (the Content-Type)
insidesyndication(), rss2(), rss2Item(), atom(), atomEntry(), rdf(), rdfItem(), rss(), commentsTitle(), commentTitle(), current(), rss2Comments(), rss2Comment(), atomComments(), atomComment()

FeedWriter final class

public/minn/src/Minn/Front/FeedWriter.php · 57 lines · Open the class →

A feed as it is written: text as given, and what each template tag and action prints, in the order the template asks for them.

methodput(string ...$text): self

Text as written.

methodtag(string $function, mixed ...$args): self

What a function that prints (a template tag) prints, called with its arguments.

methodcdata(string $function, mixed ...$args): self

What a template tag prints, for inside a CDATA section: a "]]>" in it is split so it cannot close the section (a hardening rule; the reference lets a stored name break out, contracts/front/probes.md).

staticinsideCdata(string $text): string

Text made safe inside a CDATA section: "]]>" becomes "]]]]><![CDATA[>", which a reader joins back into the same characters.

methodact(string $hook, mixed ...$args): self

What an action's callbacks print.

methodtext(): string

Everything written so far.

FrontController final readonly class

public/minn/src/Minn/Front/FrontController.php · 105 lines · Open the class →

The public site. One catch-all route: resolve the URL, then either redirect or render, through the active block theme when there is one, the classic PHP template runner when the theme is classic, and the interim template otherwise.

Kind enum

public/minn/src/Minn/Front/Kind.php · 17 lines · Open the class →

What a public URL resolved to.

Cases: Home, Single, Page, Category, Tag, Author, Date, Search, Taxonomy, PostTypeArchive, NotFound, Redirect

Maintenance final class

public/minn/src/Minn/Front/Maintenance.php · 28 lines · Open the class →

Maintenance mode, as hosting tools and updaters switch it on: a .maintenance file in the webroot whose $upgrading is less than ten minutes old. While it holds, every request gets the site's own maintenance.php (which prints its page and stops) or the 503 page; an older file is ignored.

staticanswer(string $abspath, string $contentDir, int $now): ?Minn\Http\Response

The answer while maintenance holds, or null when the site is open.

Pagination final class

public/minn/src/Minn/Front/Pagination.php · 62 lines · Open the class →

Numbered page links in the reference's shape: previous, the end and middle runs with one ellipsis per gap, the current page as a span, next.

staticlinks(array $args, Closure $link): ?array

The page links the reference's paginate_links builds, or null for one page.

@param Closure(int): string $link the URL for a page number
@return list<string>|null the link elements, null with fewer than two pages
staticformat(array $links, string $type): array|string

The links in the requested shape.

@param list<string> $links

PostEmbed final class

public/minn/src/Minn/Front/PostEmbed.php · 106 lines · Open the class →

A post as other sites embed it, the oEmbed provider side, as the reference answers (probe oembed): the data (version, the site as provider, the author or else the site, the title) through oembed_response_data, whose default makes it "rich" with the embed markup: a blockquote linking the post, a sandboxed iframe of its /embed/ page carrying a fresh secret, and the inline script that sizes it. Only a publicly viewable post is embeddable; the width is held between 200 and 600 (oembed_min_max_width) and the height is a 16:9 share of it, at least 200.

staticdata(mixed $post, int $width): array|false

get_oembed_response_data: the data, or false when the post cannot be embedded. @return array<string, mixed>|false

@return array<string, mixed>|false
staticrich(array $data, WP_Post $post, int $width, int $height): array

get_oembed_response_data_rich: the size, the markup, and a thumbnail when the post has one. @param array<string, mixed> $data @return array<string, mixed>

@param array<string, mixed> $data @return array<string, mixed>
statichtml(int $width, int $height, mixed $post): string|false

get_post_embed_html: the blockquote, the iframe and its script, through embed_html; false for no post.

staticurl(mixed $post): string|false

get_post_embed_url: the post's /embed/ address (?embed=true without pretty links), through post_embed_url.

staticxml(array $data, ?SimpleXMLElement $root = NULL): string

_oembed_create_xml: the data as an oembed document (or under the root given), nested arrays as nested elements. @param array<string, mixed> $data

@param array<string, mixed> $data
insideappend()

PostNavigation final class

public/minn/src/Minn/Front/PostNavigation.php · 36 lines · Open the class →

The links to the posts either side of this one, and the nav block that wraps them. The caller's format wraps the anchor: `%link` is the whole anchor, `%title` the post's title and `%date` its date, and the anchor carries rel="prev" or rel="next".

Titles arrive already filtered; this only assembles.

staticprevious(string $url, string $title, string $format, string $linkFormat, string $date = ''): string

A previous or next post link in the reference's format.

staticnext(string $url, string $title, string $format, string $linkFormat, string $date = ''): string

The next-post link in the reference's format.

staticariaLabel(array $args, string $default): string

The aria-label a navigation block carries: an explicit one wins, otherwise a caller-supplied screen-reader text stands in for it, and only with neither does the default apply.

@param array<string, mixed> $args the caller's own arguments
insidelink()

PrintedResponse final class

public/minn/src/Minn/Front/PrintedResponse.php · 39 lines · Open the class →

A response WordPress's handlers print themselves (a sitemap, robots.txt), as the reference serves them: the main query stood with the request's own variables and the front-end steps around it, then $print; what was printed, under the status and headers the handlers sent. A handler that ends the request early (Printed, where the reference exits) ends it here too; when none did and there is nothing to print, null, and the theme renders the page on the query as it stands.

staticstand(Minn\Theme\MainQueryBridge $bridge, array $vars, ?Closure $print = NULL, ?Minn\Front\Resolution $resolution = NULL): ?Minn\Http\Response

The request served this way, or null for the theme to render.

@param array<string, mixed> $vars the request's own query variables
insidediscard()

ProbeController final readonly class

public/minn/src/Minn/Front/ProbeController.php · 68 lines · Open the class →

The surface monitors, crawlers, and hosting checks hit that is not a page: robots.txt, the XML-RPC and cron endpoints, the admin entry point, and the favicon. Feeds and sitemaps have controllers of their own.

new__construct(Minn\Content\Site $site, Minn\Front\Permalinks $permalinks, Minn\Content\SiteIcon $icon, ?Minn\Cron\Cron $cron = NULL, ?Minn\Theme\MainQueryBridge $bridge = NULL)
methodrobots(Minn\Http\Request $request): Minn\Http\ResponseGET /robots.txt (public)

robots.txt: with plugins loaded, the reference's (the main query a robots request, then do_robots, under do_robotstxt and robots_txt); otherwise the same lines, the sitemap's only on a public site.

methodxmlrpc(Minn\Http\Request $request): Minn\Http\Response* /xmlrpc.php (public)

XML-RPC is not served; GET answers the way the reference does, POST is refused outright.

methodcron(Minn\Http\Request $request): Minn\Http\Response* /wp-cron.php (public)

wp-cron.php: runs what is due.

methodadmin(Minn\Http\Request $request): Minn\Http\ResponseGET /wp-admin (public)GET /wp-admin/{rest*} (public)

The admin is Minn Admin; the reference's admin path lands there.

methodfavicon(Minn\Http\Request $request): Minn\Http\ResponseGET /favicon.ico (public)

The site icon, or the reference's default.

QueryMoves final readonly class

public/minn/src/Minn/Front/QueryMoves.php · 119 lines · Open the class →

Where the root's archive query forms move under pretty permalinks, as the reference's canonical redirect answers them (suite permalinks): a feed (?feed=) first, then a date (?m=, ?year=), then an author by id, then a term when the query names exactly one taxonomy (?cat= or ?category_name=, ?tag=, ?taxonomy= with ?term=, a registered taxonomy's own var; ?post_format= counts as one but never moves itself), each to its pretty address with the other arguments along. Nothing moves while a search is asked for (?s=, even empty), past the first page, or to something the site does not have. The singles' forms are SingleQueries'.

Redirects enum

public/minn/src/Minn/Front/Redirects.php · 23 lines · Open the class →

Whether a resolution may answer with a canonical redirect. A GET or HEAD follows them (the trailing slash, the pretty permalink for ?p=, the guessed destination); any other method holds and resolves the path as typed, as the reference's redirect_canonical bails on a POST.

Cases: Follow, Hold

staticforMethod(Minn\Http\Method $method): self

The mode a request's method allows.

staticforRequest(Minn\Http\Request $request): self

The mode for a request: its method's (a feed's query form moves too, under the site's own host).

methodfollows(): bool

Whether a canonical redirect may be answered.

Renderer final readonly class

public/minn/src/Minn/Front/Renderer.php · 90 lines · Open the class →

The interim public theme: one clean template until the block-theme reader lands. The body-class tokens are the contract (stylesheets and crawlers key off them); the markup around them is engine-defined.

new__construct(Minn\Db $db, Minn\Front\Permalinks $permalinks)
methodbodyClasses(): array

The body classes the main query stands for (Theme\QueryClasses); none before one stands.

@return list<string>
methodrender(Minn\Front\Resolution $resolution, Minn\Content\Page $page): string

The interim page for a resolution, without a theme: a listing shows the main query's page of posts.

insidearticle(), archive()

RequestParse final class

public/minn/src/Minn/Front/RequestParse.php · 68 lines · Open the class →

The query vars the reference's request parse sets for an address (WP::parse_request), which plugins read off $wp->query_vars and get_query_var: each public var the query string or form carries, else the one the matched rewrite rule set (Front\RuleTable), all in the public vars' order (a plugin's own after the core ones); a post type's own var brings post_type and name; a path no rule matches is error=404 (the query string's error is ignored).

staticvars(array $rule, array $publicVars, array $given): array

The parse's vars, in the reference's order.

@param array<string, string> $rule the matched rule's vars
@param list<string> $publicVars the public query vars, after the query_vars filter
@param array<string, mixed> $given the query string's and the form's values
@return array<string, string|array<mixed>>
staticmismatch(array $publicVars, array $query, array $form): bool

Whether the query string and the form give a public var two different values: the reference refuses such a request (A variable mismatch has been detected, a 400) before it reads either.

@param list<string> $publicVars
@param array<string, mixed> $query
@param array<string, mixed> $form
staticqueryString(array $vars): string

The reference's query string for parse vars (WP::build_query_string): each one with a value, encoded.

Resolution final readonly class

public/minn/src/Minn/Front/Resolution.php · 116 lines · Open the class →

The outcome of resolving a public URL: which kind of thing it names, the record behind it, the page number for paginated views, and the query vars of the rewrite rule the address matched (what the request parse hands plugins). Redirects carry their target instead.

propreadonly Minn\Front\Kind $kind
propreadonly Minn\Content\PostRecord|Minn\Content\UserRecord|Minn\Content\TermRecord|array|null $record
propreadonly int $paged
propreadonly ?string $location
propreadonly int $status
propreadonly ?string $search
propreadonly ?array $date
propreadonly ?string $authorName
propreadonly bool $front

the static front page (show_on_front = page), rendered as a page that is also home

propreadonly bool $preview

a preview: the reader's autosave replaces the stored content

propreadonly bool $postsPage

the posts page (page_for_posts): the record is the page, the listing is the blog

propreadonly array $vars
methodasPreview(): self

The same resolution marked as a preview.

methodwithVars(array $vars): self

The same resolution reached through a rule with these query vars. @param array<string, string> $vars

@param array<string, string> $vars
statichome(int $paged = 1): self

The home listing.

staticsingle(Minn\Content\PostRecord $post, int $paged = 1): self

A single post or page.

staticfrontPage(Minn\Content\PostRecord $page, int $paged = 1): self

The static front page.

staticpostsPage(Minn\Content\PostRecord $page, int $paged = 1): self

The page that stands for the blog: a home listing whose record is the page.

staticterm(string $taxonomy, Minn\Content\TermRecord $term, int $paged = 1): self

A category or tag archive.

statictaxonomy(Minn\Content\TermRecord $term, int $paged = 1): self

A plugin taxonomy's term archive; the record is the term row (with its taxonomy).

staticpostTypeArchive(array $type, int $paged = 1): self

A plugin post type's archive; the record is the registered type (name, label, ...).

staticauthor(string $name, ?Minn\Content\UserRecord $user, int $paged = 1): self

An author archive.

staticdate(int $year, ?int $month, ?int $day, int $paged = 1): self

A date archive.

staticsearch(string $term, int $paged = 1): self

A search.

staticnotFound(): self

A 404.

staticredirect(string $location, int $status = 301): self

A redirect.

methodid(): int

The record's id, post or term.

Resolver final readonly class

public/minn/src/Minn/Front/Resolver.php · 325 lines · Open the class →

Turns a public URL into a Resolution the way the reference's request parse does: the root by its query string, any other path by the first of the site's rewrite rules it fits (Front\RuleTable), whose query vars name what it is (Front\RuleRoutes). What is left here are the reference's canonical answers around that (redirect_canonical, wp_old_slug_redirect):

- Unpaged content and archives without a trailing slash redirect to the slashed form, as typed (case kept), as do an embed's and an endpoint's addresses; paged views, search, and 404s do not. - Query-var forms redirect to the pretty form when the target is public: a single's (?p=, ?page_id=, ?name=, ?pagename=; SingleQueries) and an archive's (?m=, ?year=, ?author=, one taxonomy's term; QueryMoves), unless a search is asked for. - A single asked for under a category it is not in (where the structure names one), or with an old-style page number, moves to its own address; a trackback address goes to the post; the front page answers only at the root. - A name the site no longer has: the post that used to have it, else the closest published page or post whose name starts with it, pages before posts, newest first. Archives never guess. - Non-public posts are 404 to anonymous readers and served to a reader who can edit them.

new__construct(Minn\Db $db, Minn\Content\Posts $posts, Minn\Content\Terms $terms, Minn\Front\Permalinks $permalinks, Closure $canReadUnpublished, int $perPage)
@param Closure(PostRecord): bool $canReadUnpublished
staticfromDb(Minn\Db $db, Closure $canReadUnpublished): self

A resolver over the site's own settings.

methodpermalinks(): Minn\Front\Permalinks

The link builder.

methodperPage(): int

Posts per page.

methodresolve(Minn\Http\Request $request, ?Minn\Front\Redirects $mode = NULL): Minn\Front\Resolution

$canonical mirrors the reference's redirect_canonical rule: only GET and HEAD get trailing-slash, pretty-URL, and 404-guess redirects; every other method renders what the query alone finds, as typed.

staticviewableTypes(): array

The post types a guess looks among: those a reader can view that searches include.

@return list<string>
insideresolvePath(), canonical(), pagedMove(), missing(), endpointIn(), segments(), resolveQueryVars(), rootVars(), archives(), attachments(), elsewhere(), readable()

RuleRoutes final readonly class

public/minn/src/Minn/Front/RuleRoutes.php · 156 lines · Open the class →

What a matched rewrite rule's query vars name, as the reference's main query reads them (suites permalinks, plugin-rules, request-vars): a post or page by id, an attachment by name, a page (or an attachment) by its path, a post by name (of the type the vars give), a registered type's item by its own var; else a search, a category's, tag's, post format's or registered taxonomy's archive, an author's, a date's, a post type's; else the front. A rule that set error is a 404, as is a single the reader may not read. Under a name the date or category the rule also captured does not narrow the find: where the post really lives is the canonical redirect's business.

new__construct(Minn\Content\Posts $posts, Minn\Front\ArchiveAddresses $archives, int $frontPageId, int $postsPageId, Closure $readable)
@param Closure(PostRecord): bool $readable whether the reader may read a post
methodresolve(array $vars): Minn\Front\Resolution

The resolution the vars stand for. @param array<string, string> $vars

@param array<string, string> $vars
insidesingle(), archive(), typeArchive(), found(), readable(), registered(), segments()

RuleTable final class

public/minn/src/Minn/Front/RuleTable.php · 100 lines · Open the class →

An address read as WordPress's request parse reads it (suites permalinks, request-vars, plugin-rules): against the site's rewrite rules (made and stored when there are none, a plugin's own among them, each place's endpoints too), the first rule the address fits winning, as typed or decoded; a page's rule fits only when a page stands at the path it captured, under verbose page rules. A match is the rule's query vars with the matches put in. Which of them count is the request parse's business (the public vars, after the query_vars filter).

staticvars(string $path): ?array

The vars the site's rules give a path, or null when no rule fits it (or the site has none: plain permalinks).

@return array<string, string>|null
staticmatch(string $path): ?array

What the request parse makes of a path (WP::parse_request): the path under the home's, the rule it fits and that rule's query with the matches put in, and its vars; the rule and query empty when none fits. Null when the site has no rules (plain permalinks).

@return array{request: string, rule: string, query: string, vars: array<string, string>}|null
insidesubject(), first(), queryOf(), pageAt()

SingleAddresses final readonly class

public/minn/src/Minn/Front/SingleAddresses.php · 67 lines · Open the class →

The addresses a single answers to besides its own, as the reference treats them: a slug the post used to have (alone, with a page number, or with an embed or trackback suffix), and an address that puts it under a category it is not in.

new__construct(Minn\Db $db, Minn\Content\Posts $posts, Minn\Front\Permalinks $permalinks)
methodformerSlug(string $slug, int $paged = 1): ?Minn\Front\Resolution

A slug a post used to have redirects to where the post lives now, keeping the page number and dropping the query string; the lookup ignores status because the reference does (unreadable posts land on their `?p=` form and answer 404 there).

methodmisplaced(Minn\Content\PostRecord $post, array $vars): bool

Whether a post was asked for under a category it is not in, where the structure names the category: the category the address names is none at that path, or not one of the post's. The reference finds the post by its name whatever the category, then moves to its own address (a post in two categories answers under either).

@param array<string, string> $vars
methodformerSuffix(Minn\Front\Resolution $redirect, string $suffix): Minn\Front\Resolution

A former slug asked for with a suffix: embed follows the post to its new embed address, trackback goes to the post itself. The front page's redirect to the root keeps its own handling.

SingleQueries final readonly class

public/minn/src/Minn/Front/SingleQueries.php · 117 lines · Open the class →

The single a query string asks for, as the reference's request parse and canonical redirect answer it: by id (?p=, ?page_id=, any viewable type's; an attachment's goes to its own page), an attachment by id or slug (?attachment_id=, ?attachment=), a post by slug (?name=), a page by path (?pagename=). With canonical redirects on, an address that is not the single's own moves there, the other query arguments along; without, each var is strict about the type it finds.

SitemapController final readonly class

public/minn/src/Minn/Front/SitemapController.php · 65 lines · Open the class →

The sitemap index, its pages, and the two stylesheets, as the reference serves them: the request's sitemap variables stand in the main query and the sitemaps server answers at template_redirect (SitemapRequest), through every filter a plugin hooks, any provider it registers among them; what it does not print, the theme renders (a 404, or the page a stray address amounts to).

new__construct(Closure $notFound, Minn\Theme\MainQueryBridge $bridge, Closure $themed)
methodsitemapIndex(Minn\Http\Request $request): Minn\Http\ResponseGET /wp-sitemap.xml (public)

The sitemap index.

methodsitemap(Minn\Http\Request $request, string $name, string $rest): Minn\Http\ResponseGET /wp-sitemap-{name:[a-z]+}-{rest:[a-z_0-9-]+}.xml (public)

One sitemap page: a provider's name, its subtype when it has them, and the page.

methodsitemapStylesheet(Minn\Http\Request $request): Minn\Http\ResponseGET /wp-sitemap.xsl (public)

The sitemap stylesheet.

methodsitemapIndexStylesheet(Minn\Http\Request $request): Minn\Http\ResponseGET /wp-sitemap-index.xsl (public)

The sitemap index stylesheet.

methodqueried(Minn\Http\Request $request): Minn\Http\Response

The query form (?sitemap=, ?sitemap-stylesheet=) on the front page, with plugins loaded.

insideserved()

SitemapRequest final class

public/minn/src/Minn/Front/SitemapRequest.php · 71 lines · Open the class →

A sitemap request at template_redirect, as the reference's sitemaps server answers it: a sitemap address asked for another way (the query form, page 0) moves to its own; with the sitemaps off, a provider nobody registered, or a subtype or page that has nothing, the request is a 404 the theme renders; otherwise the stylesheet, the index or the provider's page is printed and the request ends. Since 7.1.3 this is where a sitemap page is judged: the main query no longer makes an empty page a 404 first, so a page a plugin fills past the page count still prints.

staticcanonical(): void

The canonical step: a sitemap asked for by another address is sent to its own.

staticserve(WP_Sitemaps $server): void

What the sitemaps server does with the request (render_sitemaps).

insidepage(), notFound()

SitemapXml final class

public/minn/src/Minn/Front/SitemapXml.php · 49 lines · Open the class →

The two sitemap documents, index and URL set, from entry maps; one builder for the engine's routes and the facade's renderer. An element with nothing inside closes itself, at every level, as the reference's XML writer prints it (probe sitemap-classes).

staticindex(array $entries, ?string $stylesheet): string

A sitemap index document.

@param list<array<string, string|null>> $entries each a map of element name => text; null values are skipped
staticurlset(array $entries, ?string $stylesheet): string

A sitemap urlset document.

@param list<array<string, string|null>> $entries
insideelements(), element(), document()

Sitemaps final class

public/minn/src/Minn/Front/Sitemaps.php · 34 lines · Open the class →

What the sitemaps share with WP_Sitemaps, which serves them: the two stylesheets browsers get when they open a sitemap, their CSS (wp_sitemaps_stylesheet_css filters it), and the date form an entry's lastmod takes.

constCSS = 'body{font:15px/1.5 sans-serif;margin:2em}table{border-collapse:collapse}td{padding:.35em 1em .35em 0;border-bottom:1px solid #ddd}'

The stylesheets' own CSS (wp_sitemaps_stylesheet_css filters it when plugins are loaded).

staticstylesheet(string $css = self::CSS): string

The engine's own stylesheet for browsers that open a sitemap.

staticindexStylesheet(string $css = self::CSS): string

The stylesheet the sitemap index links: one column, the sitemaps.

staticw3c(string $gmt): string

A GMT date as a sitemap dates it (W3C, UTC).

insidexsl()

TermLists final class

public/minn/src/Minn/Front/TermLists.php · 134 lines · Open the class →

A term's parent chain and the tag cloud, built from term rows the caller already fetched and links the caller resolves. The category list and select are the walkers' (Walker_Category, Walker_CategoryDropdown).

staticparentChain(array $line, bool $link, string $separator, bool $bySlug): string

The chain of names from the outermost ancestor down to the term itself, each one separated and optionally wrapped in its own link. The separator trails the last name too, so a breadcrumb reads "Root/Mid/Leaf/".

@param list<array{name: string, slug: string, link: string}> $line outermost first, the term itself last
statictagCloud(array $tags, array $args): ?string

The tag cloud the reference prints, or null for none: the tags sorted and cut to the number asked for (cloudTags), each one's entry (cloudData), and the links (cloudMarkup). Each row brings its "id" (for the tag-link class; its key when it has none), "scaled" (its count through the scale callback), "text" (the count in words, for the label), and its link already escaped.

@param array<array-key, array<string, mixed>> $tags
@param array<string, mixed> $args wp_generate_tag_cloud arguments
staticcloudTags(array $tags, array $args): array

The tags in the cloud's order (by name, or by count; random shuffles) and cut to the number asked for. Keys survive the sort; taking the first N renumbers the numeric ones before they name the tags.

@param array<array-key, array<string, mixed>> $tags
@return array<array-key, array<string, mixed>>
staticcloudData(array $tags, array $args): array

Each tag's entry, as wp_generate_tag_cloud_data is handed them (probe filter-inputs): id, url, role, name, the count in words and as a number, the link class, the font size, the label attribute and the shown count. Sizes step from smallest to largest across the scaled counts; a reversed range steps by one unit; an empty one leaves every tag the same size and drops the label, unless the counts are shown.

@param array<array-key, array<string, mixed>> $tags in the cloud's order
@return list<array<string, mixed>>
staticcloudMarkup(array $data, array $args): ?string

The cloud from its entries (whatever wp_generate_tag_cloud_data made of them), in the format asked for, or null for none.

@param list<array<string, mixed>> $data
insidesorted()

ToolbarMarkup final class

public/minn/src/Minn/Front/ToolbarMarkup.php · 57 lines · Open the class →

WP_Admin_Bar's markup, piece by piece, as the reference prints it (probe admin-bar): the wrapper (a skip link until the page has opened its body, a class for phones), a group's list (named by the menu it opens from), and an item: a link or an empty div, its focus order, its attributes from meta, an arrow when it opens a menu below the top level, and any markup a plugin hangs after it.

staticopen(): string

The bar's wrapper up to its first group.

staticclose(): string

The bar's wrapper after its last group.

staticgroupOpen(object $node, mixed $menuTitle): string

A group's opening list tag, labelled by the menu it opens from when that has a menu title.

staticitemOpen(object $node): string

An item up to its submenu: the list item, then its link (or a div when it has none) with its title.

staticitemClose(object $node): string

An item after its submenu: any markup a plugin hangs on it, and the list item's end.

ToolbarMenus final class

public/minn/src/Minn/Front/ToolbarMenus.php · 339 lines · Open the class →

The nodes WordPress puts on the toolbar itself, as the reference adds them on the front end for whoever is signed in (probe admin-bar): the account menu, the WordPress menu, the site menu with its appearance group, the site editor and customizer links, updates, comments, new content, the edit link for what the page shows, the shortlink, the secondary groups, and the search box. Each is one admin_bar_menu callback, so plugins can unhook any of them by name.

constMENUS = array ( 0 => array ( 0 => 'wp_admin_bar_my_account_menu', 1 => 0, ), 1 => array ( 0 => 'wp_admin_bar_my_account_item', 1 => 9991, ), 2 => array ( 0 => 'wp_admin_bar_recovery_mode_menu', 1 => 9992, ), 3 => array ( 0 => 'wp_admin_bar_search_menu', 1 => 9999, ), 4 => array ( 0 => 'wp_admin_bar_sidebar_toggle', 1 => 0, ), 5 => array ( 0 => 'wp_admin_bar_wp_menu', 1 => 10, ), 6 => array ( 0 => 'wp_admin_bar_my_sites_menu', 1 => 20, ), 7 => array ( 0 => 'wp_admin_bar_site_menu', 1 => 30, ), 8 => array ( 0 => 'wp_admin_bar_edit_site_menu', 1 => 40, ), 9 => array ( 0 => 'wp_admin_bar_customize_menu', 1 => 40, ), 10 => array ( 0 => 'wp_admin_bar_updates_menu', 1 => 50, ), 11 => array ( 0 => 'wp_admin_bar_command_palette_menu', 1 => 55, ), 12 => array ( 0 => 'wp_admin_bar_comments_menu', 1 => 60, ), 13 => array ( 0 => 'wp_admin_bar_new_content_menu', 1 => 70, ), 14 => array ( 0 => 'wp_admin_bar_edit_menu', 1 => 80, ), 15 => array ( 0 => 'wp_admin_bar_add_secondary_groups', 1 => 200, ), )

WordPress's menus as add_menus hooks them: the callback, its priority.

staticmyAccountItem(WP_Admin_Bar $bar): void

"Howdy" with the user's name and small avatar, at the right of the bar.

staticmyAccountMenu(WP_Admin_Bar $bar): void

The account menu: the user's card (larger avatar, name, login when it differs, the profile link) and Log Out.

staticsidebarToggle(WP_Admin_Bar $bar): void

The menu button wp-admin's narrow screens show; the front end has none.

staticwpMenu(WP_Admin_Bar $bar): void

The WordPress logo's menu: About and Get Involved for a reader, then the wordpress.org links beside them.

staticsiteMenu(WP_Admin_Bar $bar): void

The site's name (with its icon when it has one), then the dashboard, appearance and plugins below it.

staticappearanceMenu(WP_Admin_Bar $bar): void

The appearance group under the site's name: themes, then what the theme supports for those who may edit it.

staticeditSiteMenu(WP_Admin_Bar $bar): void

Edit Site under a block theme, opening the template this page was built from when there is one.

staticcustomizeMenu(WP_Admin_Bar $bar): void

Customize, for a theme the customizer serves (a block theme only once something registers with it).

staticupdatesMenu(WP_Admin_Bar $bar): void

The count of updates waiting, when there are any.

staticcommentsMenu(WP_Admin_Bar $bar): void

The comments awaiting moderation, for those who edit posts.

staticnewContentMenu(WP_Admin_Bar $bar): void

New: a post, media, a link, a page, each other type shown on the bar, and a user, as far as the user may create them.

staticeditMenu(WP_Admin_Bar $bar): void

Edit, for the post, term or user the page shows, when the user may edit it.

staticshortlinkMenu(WP_Admin_Bar $bar): void

The page's shortlink, with a box to copy it from.

staticsecondaryGroups(WP_Admin_Bar $bar): void

The groups for the bar's right side and the logo menu's outside links.

staticrecoveryModeMenu(WP_Admin_Bar $bar): void

The way out of recovery mode, while the site is in it.

staticsearchMenu(WP_Admin_Bar $bar): void

The search box, on the front end.

insideprofileUrl(), creatable(), editPost(), editTerm()

ToolbarTree final class

public/minn/src/Minn/Front/ToolbarTree.php · 90 lines · Open the class →

WP_Admin_Bar's nodes bound into the tree they print as, as the reference binds them (probe admin-bar): each gains its children and its type; an item's children go into its "-default" group, made when the first one arrives; a group inside a group sits next to it in a "-container", put where the outer group was; a node whose parent is missing is left out. The bar's own node accessors are used throughout, so a subclass that overrides them still sees every node it is asked for.

staticbind(array $nodes, Closure $get, Closure $set): ?object

The root of the bound tree, for nodes (the bar's, a root among them) reached through the bar's accessors.

@param array<string, object> $nodes
@param \Closure(string): ?object $get
@param \Closure(array<string, mixed>): void $set
insideplace(), defaultGroup(), container()