=== Broadside === Contributors: shadowsoftware Requires at least: 6.6 Tested up to: 7.0 Requires PHP: 8.0 Stable tag: 1.3.4 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Tags: news, blog, one-column, two-columns, three-columns, custom-colors, custom-logo, custom-menu, block-patterns, block-styles, editor-style, featured-images, full-site-editing, rtl-language-support, style-variations, template-editing, translation-ready, wide-blocks A broadsheet block theme for news publications: blackletter masthead, folio rule, three-column lead grid, and the furniture a long read needs. == Description == Broadside dresses a WordPress site as a broadsheet newspaper. The front page is a three-column lead grid: a rail of briefs, a lead story set in two justified columns with a drop cap, and a photo with the day's secondary story beside it. Above them sits a blackletter nameplate flanked by two "ears", a folio rule carrying the volume, the date and the motto, and a section navigation. Below them, an index of every section and its latest headlines, built from your categories. Articles get the furniture a reported feature actually needs, as blocks: * **Short Answer** — a direct, quotable answer at the top, for the reader in a hurry and the search engine that wants to cite you. * **Key Takeaways** — the three or four things a reader should leave with. * **Table of Contents** — builds itself from your headings. Rename a heading and the contents follow; there is nothing to keep in sync by hand. * **FAQ** — questions and answers that also emit FAQPage structured data. * **Sources & References** — the receipts. * **Disclosure Table** — a comparison table whose partner links are always marked `rel="sponsored nofollow"` and which always prints a disclosure line. * **Byline**, **Author Bio** and **Editorial Standards** — the trust signals a journal of record is judged on. = One theme, two publications = Broadside hard-codes no brand. The accent colour, the founding year, the city of record, the strapline, the motto, the cover price, the volume, the newsletter's name and the masthead "ears" are all Customizer settings. Two sites running Broadside can look like two entirely different journals — one a green cannabis trade weekly, the other an oxblood shooting-sports monthly — from the same code. = What Broadside does not do = Broadside renders a newsletter signup form and hands the address to whatever endpoint you name in the Customizer. It **stores no subscribers and sends no mail**. That is deliberate: your subscriber list is yours, and a theme that held it would lose it the day you switched themes. Point the form at your own automation, mailing-list provider, or webhook. Broadside also emits NewsArticle, Organization, BreadcrumbList and FAQPage structured data — but only when no SEO plugin is active. If Yoast, Rank Math, SEOPress or All in One SEO is running, they own the schema graph and Broadside gets out of the way, because two competing graphs on one page is worse than none. = Accessibility = Broadside ships sensible defaults: a working skip link, a visible focus style on every interactive element, correct heading order (the nameplate steps down from `h1` to `p` on any page where an article headline is the real `h1`), form labels on every input, `prefers-reduced-motion` honoured, and colour contrast that passes AA on the default palette. The Customizer will let you pick an accent that fails contrast — it is your publication — but the defaults do not. This theme does **not** claim the WordPress.org `accessibility-ready` tag. That tag triggers a separate, longer review queue. == Installation == 1. In your WordPress admin, go to Appearance → Themes → Add New. 2. Search for "Broadside", then click Install and Activate. 3. Go to Appearance → Customize → Broadside and set your accent colour, founding year, city, strapline and motto. 4. Go to Appearance → Editor to adjust the templates, or start writing — the theme works out of the box. To reproduce the front page, you need a handful of published posts: the most recent becomes the lead story, the next four fill the briefs rail, and the sixth becomes the secondary story beside the photo. == Frequently Asked Questions == = Does Broadside require a page builder? = No. Broadside is a block theme built on core WordPress. It requires no plugin at all, and it deliberately does not depend on Elementor, Divi, or any other page builder — your layouts stay in your theme's files, under version control, rather than in your database. = Where do subscribers go when someone signs up? = Wherever you send them. Broadside renders the form and posts it to the endpoint you set in Customizer → Broadside → Newsletter. If you set no endpoint, no form is rendered — Broadside will not show a form that silently throws addresses away. = The table of contents is empty. = It builds itself from the `h2` and `h3` headings in the post. A post with no headings has no contents to list. Add a heading and it appears. = Can I use my own logo instead of the blackletter nameplate? = Yes. Set a custom logo under Customizer → Site Identity and it replaces the type entirely. You can also switch the nameplate to a cleaner display serif under Customizer → Broadside → Masthead. = Why does the drop cap look wrong in my language? = The drop cap uses `::first-letter`, which behaves differently across scripts. Turn it off under Customizer → Broadside → Article furniture if it does not suit your language. == Copyright == Broadside, Copyright 2026 Shadow Software LLC. Broadside is distributed under the terms of the GNU GPL v2 or later. Broadside bundles no third-party code. It bundles four typefaces, all under the SIL Open Font License 1.1, which is GPL-compatible. The copyright lines below are transcribed from each font's own embedded metadata, not from a distributor's page. UnifrakturMaguntia (assets/fonts/unifraktur-maguntia-400.woff2) Copyright (c) 2010, j. 'mach' wust, with Reserved Font Name UnifrakturMaguntia. Copyright (c) 2009, Peter Wiegel. Licensed under the SIL Open Font License, Version 1.1. Source: https://fonts.google.com/specimen/UnifrakturMaguntia License: https://scripts.sil.org/OFL Libre Caslon Display (assets/fonts/libre-caslon-display-400.woff2) Copyright 2012, The Libre Caslon Display Authors (https://github.com/impallari/Libre-Caslon-Display). Licensed under the SIL Open Font License, Version 1.1. Source: https://fonts.google.com/specimen/Libre+Caslon+Display License: https://scripts.sil.org/OFL Source Serif 4 (assets/fonts/source-serif-4-normal.woff2, source-serif-4-italic.woff2) Copyright (c) 2014-2021, Adobe Systems Incorporated (https://adobe.com/), with Reserved Font Name 'Source'. Licensed under the SIL Open Font License, Version 1.1. Source: https://fonts.google.com/specimen/Source+Serif+4 License: https://scripts.sil.org/OFL The full text of the SIL Open Font License 1.1 ships with this theme at assets/fonts/LICENSE-OFL.txt. The full text of the GNU GPL v2 ships at LICENSE. The screenshot (screenshot.png) is a rendering of the theme itself, created by Shadow Software LLC and licensed GPLv2 or later. It contains no third-party imagery, no stock photography and no logos. Broadside bundles no images, no icons, no SVG artwork and no JavaScript libraries. Everything else in the theme zip is original code by Shadow Software LLC, licensed GPLv2 or later. == Upgrade Notice == = 1.3.4 = Theme Directory review fixes: drop the accessibility-ready tag (separate a11y queue) and remove Theme URI (GitHub is not a valid Theme URI). = 1.3.3 = Fixes a grey band printed across the masthead on any site that has not chosen a masthead device. The band was the device's own ink, painted with nothing masked out of it. If you do use a device, it is unchanged. = 1.3.2 = The newsletter form now submits without a page reload when JavaScript is available, showing an inline confirmation instead. Plain form submission still works exactly as before if JavaScript is off — nothing to configure. = 1.3.1 = Housekeeping. Broadside Blocks now has its own repository and its own release zips, and the two are back on the same version number. Nothing on your site changes. = 1.3.0 = New: a masthead device — an engraved ornament printed faintly behind the nameplate. Set one under Customizer → Broadside → Masthead. Nothing changes if you don't. = 1.2.1 = Fixes headlines printing `'` and `"` as visible text, and the same entities leaking into the structured data that search engines read. = 1.2.0 = The blocks now live in a companion plugin, Broadside Blocks, which WordPress will offer to install alongside the theme. Without it you get the paper, the type and the grid, but no nameplate, folio or editorial blocks. = 1.1.1 = The theme is now called Broadside. It was called Digest, and a different author already has a theme by that name in the Theme Directory. The text domain moves with it, so a site running the old build should reapply its Customizer settings. = 1.1.0 = The front page's lead photograph is no longer lazy-loaded. If you run Broadside on a site that is measured on Core Web Vitals, this release is worth taking. == Changelog == = 1.3.4 = * Theme Directory review: remove the `accessibility-ready` tag so review is not held for a separate accessibility queue. Keep skip-link and focus styles. * Remove Theme URI (was a GitHub URL — not about the theme on WordPress.org). * Customizer settings audited; every registered setting is still used at runtime. = 1.3.3 = * Fix: a solid grey band was printed across the masthead on every site with no masthead device chosen — which is to say, by default. The device is drawn by masking a rectangle of ink; with no device the mask was set to `none`, and in CSS `mask-image: none` means "no mask" rather than "mask everything", so the bare ink rectangle was painted at full size. The ink is now only laid down when there is actually a device to carve out of it. = 1.3.2 = * The newsletter form is now progressively enhanced: with JavaScript available it submits via `fetch` and shows an inline "check your inbox" or error message in place, instead of reloading the page. With JavaScript unavailable, or if the request fails to even start, the form's real `action`/`method` attributes mean a plain submit-and-reload still works — nothing about how the endpoint receives the address has changed. * Corrected a leftover "Pressroom" name in the newsletter block's description. = 1.3.1 = * Broadside Blocks now lives in its own repository, with its own CI and its own release zips. The theme and the plugin ship together, so they are back on the same version number — a reader should never have to work out which pairs with which. * Nothing on your site changes. This is repository housekeeping. = 1.3.0 = * **New: the masthead device.** An engraved ornament — a furled flag, a botanical plate, a coat of arms — printed faintly behind the nameplate, the way a real broadsheet prints one. Set it under Customizer → Broadside → Masthead, with a strength control; leave it empty and the masthead is exactly as it was. * This is deliberately NOT the article page's photographic backdrop, though both are "an image behind text". A photograph has to be beaten into submission to sit behind a headline — desaturated, flattened, faded. An engraving is already quiet: it is ink. So the device is not drawn as a picture at all. Supply a PNG whose line-work is its transparency, and the theme uses it as a MASK on its own ink colour — which means one file prints correctly on cream paper, on a dark style variation, and in whatever colour a given publication's ink happens to be. * It removes itself where it would do harm: under `prefers-contrast: more`, and on phones, where a masthead is barely wider than the nameplate and an ornament designed to sit at the flanks has no flanks left to sit in. * No device ships with the theme. A theme that shipped a flag would be a theme with a nationality, and this one dresses two publications that have nothing in common. = 1.2.1 = * **Fixed: headlines printed `'` and `"` as visible text.** A title whose punctuation is stored as an HTML entity — which happens when the post is created by an automation rather than typed into the editor — was being escaped a second time by the theme, turning `'` into `'`, which a browser renders as the literal characters. It showed on the front page's section index and in the related-posts rail beneath every article. * **Fixed: the same entities were reaching search engines.** In JSON-LD it was not a display bug but a data bug: a JSON string is never HTML-decoded, so Google was being served `"headline":"CNBC's "Best States"…"` and would index exactly that. The article headline, the organisation name, the site tagline, the breadcrumb, the FAQ questions and the meta description were all affected. * The theme now decodes a title or excerpt to plain text once, then escapes it for whichever context it is going into — HTML or JSON — instead of assuming WordPress has not already done it. New helper: `shadow_digest_plain_text()`. * The sandbox now seeds a post whose title carries literal entities, and four new assertions check that nothing is escaped twice. Every seeded title before this had either real punctuation or none, so 36 green assertions had nothing to say about a bug that was live on a production site. = 1.2.0 = * **Renamed to Broadside, and the blocks moved to a companion plugin.** Two changes, both required by the WordPress.org Theme Directory, and both worth making anyway. * The 17 blocks now live in **Broadside Blocks**, a separate plugin. The Theme Directory lists "Custom blocks" as plugin territory, and a theme may not register one. The rule's test is the right one: anything a user LOSES when they switch themes belongs in a plugin. A Short Answer, an FAQ and a Sources list are content — they live in your post, and shipping them inside a theme means changing theme silently blanks them. WordPress 6.5+ reads the theme's `Requires Plugins` header and offers to install the plugin for you. The theme still works without it: you get the paper, the type and the grid, and WordPress simply omits the blocks it cannot find. * Fixed: **the blocks were never in their own editor category.** The theme registered a category with one slug while all 17 `block.json` files asked for another, so every block quietly landed in the editor's default bucket and the custom category sat empty. It had been that way since 1.0.0. * The theme was previously called Pressroom, and before that Digest. Both names were already taken — Digest by another theme in the Directory, Pressroom by an established commercial news theme with 500+ installs. Broadside was verified free on the Theme Directory, on the Plugin Directory, and on the open web before it was chosen. A broadside is a sheet printed on one side: historically, a single-sheet news publication. = 1.1.1 = * **Renamed: Digest is now Broadside.** A theme called Digest already exists in the WordPress.org Theme Directory, by a different author. Sharing a name is not just a submission problem — WordPress matches theme updates by slug, so a site running this theme under a name someone else owns could be auto-updated to a stranger's theme. The slug, the text domain and the block namespace move with the name. * The bundled fonts' copyright lines are now transcribed from each font's own embedded metadata rather than from a distributor's web page. Three were wrong: Libre Caslon Display is "Copyright 2012 The Libre Caslon Display Authors" (not 2019, Impallari et al.); Source Serif 4 is 2014-2021 Adobe Systems Incorporated (not 2014-2023); and UnifrakturMaguntia had its two authors' years transposed. All four remain SIL OFL 1.1, which is GPL-compatible. Nothing about what the theme is allowed to ship has changed — only the accuracy of what it says about it. * Added the Upgrade Notice section required of a Theme Directory readme, and cut the short description to 142 characters (the limit is 150; it was 168). = 1.1.0 = * **Fixed: the front page's lead photograph was lazy-loaded.** WordPress decides for itself which image to fetch eagerly — it takes the first "content" image on the page, marks it `fetchpriority="high"` and exempts it from lazy-loading. On an article page it picks correctly. On the front page it did the exact opposite: the lead photograph sits inside a group inside the query loop, which WordPress reads as a below-the-fold list thumbnail, so the single largest visible element of the site's most important page was served `loading="lazy"` and `fetchpriority="low"` — and nothing on the page was marked high priority at all. The browser would not begin fetching it until layout had run, then queued it behind everything else. Digest now tells WordPress the fact only the theme knows: on the front page, the first featured image IS the hero. The briefs rail and the secondary story stay lazy, because they genuinely are further down. * The theme now builds its own WordPress.org submission package (`./scripts/package.sh`), and verifies the bytes that would actually be uploaded rather than the working tree they were copied from. This caught two dev dotfiles that were shipping inside every hand-made zip: they live in the theme directory, so `.distignore`'s root-anchored rules could never match them. * The guard against the 2026-07-13 outage bug now tokenizes the PHP instead of grepping it, and is itself unit-tested (`./scripts/guard-selftest.sh`, 16 cases). The old grep could not tell a live `do_blocks()` call from a comment warning against one — it had been failing the build on every single run, flagging the comment that documents the rule. A build that is always red teaches people to stop reading it, which is worse than having no guard. = 1.0.12 = * The front page's lead story now carries its featured image as a BACKDROP behind the headline — the same treatment an article page gives it (1.0.10), so the two finally match. The lead previously had no image at all, which meant the biggest story on the paper was the only one with nothing to look at. * Story cards respond to the cursor. Hovering a card warms its photograph and pulls its headline to the accent — quietly; a broadsheet does not lift, scale or bounce. This is confined to `@media (hover: hover)`, so a phone does not leave a card stuck in its hover state after a tap, which is what a plain :hover rule would do. * The paper now reaches the bottom of the screen. The sheet was drawn exactly as tall as the content sitting on it, so a short page — My Account is a login card and a footer — stopped part-way down and left the rest of the viewport as bare desk, reading like a page that had failed to finish loading. It now fills the viewport (using `dvh`, so mobile browser chrome does not produce a scrollbar that scrolls to nothing) while a long page stays free to be longer. = 1.0.11 = * **Fixed: the cart and the checkout were rendering with no masthead at all.** WooCommerce ships its own block templates for Shop, Product, Cart and Checkout, and every one of them asks for a template part called `header`. Digest's is called `masthead`. WordPress found no `header`, so those four pages — the four a customer passes through on the way to paying — dropped the nameplate, the folio and the section navigation, and printed "Template part has been deleted or is unavailable: header" where the newspaper should have been. Digest now provides a `header` part, so a plugin that follows the WordPress convention finds what it expects. * WooCommerce is now dressed in the newspaper's own clothes. Every page the plugin adds — the shop, a product, the cart, the checkout, My Account and its order history — is set in the theme's type, on the theme's paper, using the theme's rules and its oxblood accent. Digest treats WooCommerce's two eras (the React blocks of the shop and cart; the older PHP templates of My Account) as one shop, so the site does not change typeface when a reader logs in. * The catalogue is a plate, not a card. Product photographs arrive in whatever shape the supplier sent, and WooCommerce prints them at their natural ratio, so a row of products ends at a row of different heights. Every plate is now cropped to 4:5 and centred, and — because cropping an already-cropped thumbnail loses detail twice — the theme asks WooCommerce to GENERATE the 4:5 crop rather than crop its square one again. * A product with no photograph no longer punches a grey hole in the page: the placeholder is tinted to the paper and faded back, so it reads as an absence rather than as an error. * Buttons are declared once, in theme.json, as the theme's global button. Before, the theme had no opinion on what a button was, so WooCommerce's own slate-blue pill won by default — on every Add to Cart, on the login form, and at checkout. * Entirely optional. With no WooCommerce installed none of this matches anything, and Digest remains a theme with no plugin dependency that runs on stock WordPress. * New: `./scripts/shoot.sh` screenshots every page of the theme — including every shop page — at desktop and mobile, and builds a contact sheet putting the two side by side. The sandbox (`./scripts/local-wp.sh up`) now builds a WooCommerce shop as well as a newspaper, stocked with the awkward cases: a sale price, an out-of-stock item, a product with no image, a variable product, and a name long enough to wrap. = 1.0.10 = * The featured image is no longer a slab between the headline and the article. It is now a BACKDROP: bled to the edges of the sheet behind the eyebrow, headline, deck and byline, faded down into the paper and dissolved out on all four sides. The reader meets the headline first, with the photograph behind it, and the article body begins immediately underneath — there is nothing to scroll past. (1.0.9 clamped the slab's proportions and capped it at 88vh, which turned a 1120px square into a 1120x792 letterbox: smaller, but still most of a screen of picture standing between the headline and the first word. Taming the slab was the wrong idea; the slab was the problem.) * Verified: worst-case contrast behind the headline measures 9.77:1 against the darkest pixel of the backdrop — comfortably past WCAG AA. The treatment is removed entirely under prefers-contrast: more. * WooCommerce account and cart links in the utility bar, in the cell that has always been empty on both sites. Entirely optional: renders nothing at all when WooCommerce is not installed, so the theme still works on stock WordPress. * Fixed: the section grid ("Inside this week's edition") had no left border. The cells drew only their right and bottom edges, so the box closed on three sides by coincidence and the left was simply never drawn. * Fixed: the masthead ears are now optically balanced. They were both bottom- aligned, but the left ear runs to three lines against the right's two, so the taller one started higher and read as though only one were centred. = 1.0.9 = * Tamed the featured image on single posts and pages. It previously had no styling at all, so its height was dictated entirely by whatever the editor uploaded: a tall portrait rendered 2,240px high on a 1440x900 desktop — 249% of the viewport, two and a half screens of picture before the first word of the article — while a panoramic crop came out as a 373px letterbox slit. * The hero's proportions are now clamped into a band (no wider than 2.4:1, no taller than 4:3 on desktop / 4:5 on phones). An image whose shape is already reasonable is left completely untouched — an ordinary 16:9 photo passes through with no crop at all — and only a pathological one is overridden, cropped from the centre. * A hero is now capped at 88vh, so the top of the article body is always within reach no matter how tall the source image. * Undersized uploads are no longer blown up. A 320px-wide image was being stretched across the full 1120px sheet (a 3.5x upscale, visibly soft); it now sits centred at its true size, sharp. * No layout shift: the aspect ratio is printed server-side, so the box reserves its final height before the image has loaded a single byte. = 1.0.8 = * Added a meta description to every page (singular posts/pages, category and tag archives, author archives, the front page) — stock WordPress prints none, which left every page's search-result snippet to chance. * Added a canonical link to the front page and every category, tag and author archive (including their paginated pages). WordPress core's rel_canonical() only ever covers singular posts and pages; every other page type was silently uncanonicalised. * Stopped enqueueing style.css as a front-end stylesheet. It carries only the theme header comment and no CSS rules; WordPress reads the header directly and never required the file be loaded in the browser, so this was a render-blocking HTTP request that improved nothing. = 1.0.1 = * **Fixed a fatal infinite recursion in the table-of-contents block.** It rendered the post content in order to find the headings, which re-rendered every block in that content — including itself — with no base case. Any article containing the block would hang the request forever. It now reads the raw post content, where the heading markup already lives, and renders nothing. * Added a re-entrancy guard around every block render callback, so that no future bug of this shape can hang a request: a block that re-enters itself now returns empty instead of recursing. * Author avatars no longer block page rendering on a Gravatar request. A site whose outbound HTTP is firewalled would hang on every avatar; Digest now prefers a locally-uploaded image, and falls back to a printed monogram. * Replaced the related-posts query with a block that cannot recommend the article the reader is already on. * Fixed related-post cards running their kicker, headline and summary together on one line. * The newsletter panel no longer holds open an empty second column when no signup endpoint is configured. = 1.0.0 = * Initial release.