Skip to content

Releases: BizzCMS/bizzcms

BizzCMS 0.2.12

Choose a tag to compare

@idubravac idubravac released this 25 Oct 09:21

Added

  • Analytics plugin (src/plugins/analytics.ts, optional, Admin › Plugins › Analytics): the site's own visitor statistics without cookies or personal data (daily anonymous visitor hash, salt deleted after 2 days; bots left out). Admin › Analytics: visitors, page views, change vs the previous period, daily chart, pages, referrers, countries, devices and UTM campaigns. Can run alongside Google Analytics. Sites wire analyticsHit (POST /_bz/hit), withAnalytics and analyticsAdminRoute.
  • Directory plugin: contactsGate: phone and e-mail only for some visitors (e.g. signed-in couples). Profile pages and their structured data never contain them; a locked box asks the site's address (path?s=<slug>, JSON, 401/403) when the visitor is signed in. With the gate the website and social links are protected the same way (address stays public); the box has one sign-in button, and none when the profile has the inquiry button (that already sends signed-out visitors to sign-in).

BizzCMS 0.2.11

Choose a tag to compare

@idubravac idubravac released this 23 Oct 18:17

Changed

  • Cookie bar: its title is a styled paragraph (.bz-title, role heading) instead of an <h2>, so it never adds a heading to the page outline (search engines render the bar for every first-time visit).
  • Directory plugin: company card images use the company name as alt text.

BizzCMS 0.2.10

Choose a tag to compare

@idubravac idubravac released this 23 Oct 18:10

Added

  • Article social tags: posts get article:published_time, article:modified_time, article:section (main category) and up to six article:tag from seoHead()/socialTags() (SeoHead.article), so LinkedIn, Facebook and others show the date and topic.

Changed

  • Structured data: articleSection lists the main category first and at most two (a long list of loosely related categories blurs the topic).

BizzCMS 0.2.9

Choose a tag to compare

@idubravac idubravac released this 23 Oct 17:51

Security

  • Engine 3.0.0-beta.28-bizzcms.1 (from BizzCMS/bizzcms-core): seed-admin only in development/test, production refuses to run without JWT_SECRET, OAuth never links an account by e-mail alone, escaped admin user and form pages, sandboxed SVG/HTML uploads with nosniff, admin-only /api/system/info|stats|env, admin permission check fails closed, admin scripts pinned with integrity hashes.
  • Better Auth 1.6.33 (latest 1.6), pinned with overrides (better-auth, @better-auth/core, @better-auth/drizzle-adapter, @better-auth/telemetry). Sites copy the same overrides.

Added

  • Schema map for AI agents (SEO › Indexing, on by default): /schemamap.xml lists one structured-data feed per content type (/schema/<part>.ndjson, newline-delimited JSON: organisation and website once, then every published, indexable post as Article and page or collection item as WebPage). Same layout as NLWeb schema maps, so AI agents can read a whole site in one request. Follows the sitemap rules, is listed in robots.txt (Schemamap:), kept at the edge until content changes, and shown in SEO › AI Discovery. seoSitemap() answers the new paths; sites with their own sitemap call seoSchemaMap(url, db).
  • Image source records (engine 3.0.0-beta.28-bizzcms.10): every image in the media library can store its source link, author and licence (Admin > Media > file details; stored only, never shown on public pages). upload_media takes source (link to the original page), credit and license; the old free-text source is no longer copied into the caption (Izvor: ...), so nothing about the source can reach a page.
  • E-mail confirmation for site accounts: configureAccounts({ confirmSince }) makes every account opened from that moment (by any route) confirm its e-mail before it can be used: the sign-up sends a link (hashed, valid 7 days) instead of signing in, sign-in is refused and a session from elsewhere is ignored until confirmed, "send the link again" never reveals whether an account exists. Older accounts, Google sign-ups and invitation activations are not affected. New texts confirm*, paths confirm/confirmed, e-mail confirmEmail; the registered hook and the welcome e-mail follow the confirmation.
  • Table setup once per deploy (src/schema-once.ts): the shared files' CREATE TABLE IF NOT EXISTS and plugin-record steps run once per isolate, and once per deploy with configureSchemaOnce({ kv, deployId }) plus [version_metadata] in wrangler.toml (docs/caching.md). Engine 3.0.0-beta.28-bizzcms.9 does the same for its bootstrap.
  • Directory plugin: featuring: featuredUntil on a profile puts it first in the default and Recommended order, suggestions and featured lists, with a "Featured" label (text.featured); Plan.featureMonths.
  • Directory plugin: imported owners: activation lets an account without a password (imported from an old site) set one and signs it in; ownerPending on the profile is cleared. signInSession() in site-accounts.
  • Directory plugin: params.defaultSort: the order used when the address has no sort (e.g. newest first); that order needs no parameter and Recommended gets its own value (params.sortRecommended).
  • Directory plugin: notify hook: setDirectory({ notify }) is called after a date request, a profile claim or a new company profile is saved (DirectoryEvent), e.g. to send e-mail; errors never fail the save.
  • Directory plugin: region (county) pages: optional routes.region (e.g. /companies/region/{slug}/) gives each region a clean, indexable page in the sitemap; a region chosen in the filter redirects there; regionUrl().
  • Directory plugin: clean filter addresses: empty parameters are dropped (301), a directory search with a category or city goes to that category/city page with the other filters (?region=…&guests=…), and GET forms no longer send empty fields.
  • Directory plugin: taxonomy.priceFilter (default true): false hides the price filter in the directory sidebar; price levels stay on profiles and in the portal.
  • Directory plugin: unique profile titles: Name - (sub)category, city when the company has no own SEO title (an imported SEO title equal to the name counts as none), so same-named companies never share a <title>.
  • MCP publish date: create_<collection> and publish_<collection> take an optional publishedAt (ISO 8601 date or date-time, or unix seconds; not in the future), so imported or historical articles go live with their own date and sort correctly (docs/mcp.md › Publish dates).
  • MCP upload_media: adds an image from an https link or base64 to the media library in the site's own folder and returns the /files/... path for featuredImage; alt text, caption, tags and a source/licence note are stored. Safe fetch: https only, no IP addresses or internal host names, redirects checked, JPEG/PNG/WebP/GIF/AVIF only, 10 MB at most; the link (which may carry a key) is never stored or echoed. Listed only for callers with write access (docs/mcp.md › Media upload).
  • MCP categories: list_/get_/create_/update_/publish_/delete_categories, with read and write following the per-collection MCP access settings.
  • MCP unique slugs: create_<collection> refuses a slug that an existing item of that collection already uses.
  • All MCP additions live in src/mcp-extras.ts; sites route POST /mcp through mcpWithExtras(request, db, upstream, { mediaFolder }).

Fixed

  • MCP writes did not renew the edge cache: pages caught up after a few minutes, but sitemaps and feeds stayed old until the next save in the admin. A successful MCP create, update, publish or delete now renews it like an admin save.
  • docs/mcp.md listed tool names that do not exist (create_page, create_post); the tools are create_<collection>, update_…, publish_…, delete_….

Changed

  • MCP: "MCP Settings" is a black button right after the Settings / Information / Activity Log tabs on the MCP plugin page (was a banner above the page). The "Collection write access" card sits in the MCP dashboard's column in the same card style, and the example configs name the server bizzcms.

BizzCMS 0.2.8

Choose a tag to compare

@idubravac idubravac released this 10 Oct 16:58

Added

  • Directory plugin in the admin menu: directoryPlugin() adds Directory (companies), booking requests and listing claims to the plugin menu.
  • Directory plugin: share buttons on company profiles through the new share setting (e.g. the Social Share plugin in the page language); wrapper .dir-share.
  • Languages plugin (src/plugins/languages.ts, docs/languages.md): a site in several languages, each on its own addresses (/, /en/, /de/…). Translations are pages with a Translation of field. Every public page gets <html lang>, hreflang + x-default, og:locale and a language switcher in [data-bizz-languages].
  • SEO › General › Site language: RSS <language> and feed texts in the site language (English, Croatian, German), inLanguage on WebSite and WebPage; seoHead takes an optional page language.
  • Cookie bar: a link with data-cookie-policy on the page (e.g. the footer link in the page language) is used as the policy link. Cookie bar texts in German. Share buttons in English, Croatian and German (shareBar(…, lang)). setSponsoredLabels() for the "Sponsored" labels.

Fixed

  • Sign-in: one message at a time in one style. A failed sign-in showed upstream's old red box under the page alert; it now looks like the alert (icon, colours) and replaces it. The "Create one here" link is gone (registration is closed).
  • RSS feeds always said <language>en</language> and "The post … appeared first on …", also on Croatian sites.

Changed

  • Cookie bar in the Cookiebot style (Google Analytics plugin): full-width bar with Necessary / Preferences / Statistics / Marketing switches, details, and Allow all · Allow selection · Use necessary cookies only; English and Croatian built in (page language). Google Consent Mode advanced: gtag.js is on every page, cookies and identifiers only after Statistics is allowed (the current page is counted then, once). New settings: Banner title, Button colour, Button text colour.

Fixed

  • Page titles no longer end in the host name ("… | localhost") when SEO › General › Site name is empty: the company name is used, else no suffix.

Fixed

  • Google Analytics (consent): Accept after Reject on the same page now grants analytics again (it was ignored once gtag.js had loaded). The snippet guards against running twice, so GA4 is configured once per page and sends one page_view. Any other gtag.js tag on a public page (a template or pasted HTML) is removed while the plugin is active, so the plugin is the only GA4 integration and nothing loads before consent.

Fixed

  • /sitemap_index.xml, /sitemap-index.xml, /wp-sitemap.xml, /sitemap1.xml and /sitemap.xml.gz (names from WordPress/Yoast that crawlers and checkers try) 301 to /sitemap.xml instead of 404.

Added

  • Directory plugin: Keywords field per company (search matches it) and Online check fields (result, date, notes) for staff.
  • Directory plugin (src/plugins/directory/, docs/directory.md): a company directory with filters, category and city pages, company profiles with a gallery, date requests for Premium companies, and a company portal (sign up, add, edit and claim a profile, photos, requests). Addresses, query words, categories, regions, wording and layout are set per site with setDirectory(); English by default. Visitor accounts for public areas (sign in, register, photo galleries) are shared in src/site-accounts.ts.

Fixed

  • Saving a published post no longer changes its dates. The engine wrote each save as a new version with created_at = now and then set published_at = now, so edited posts jumped to the top of the blog, the RSS feed and the Content list, and got a new datePublished. The new version now keeps created_at and published_at; only the first publish sets the date (src/publish-date.ts).

Changed

  • Content lists sort by Created (newest first) instead of last update, so saving an item no longer moves it to the top. New Created column next to Updated; both headers sort the whole list (?sort=created|updated&dir=desc|asc). Created is the earlier of created and published date, so imported posts show their original date (src/content-dates.ts).

Fixed

  • Lookup indexes (src/db-indexes.ts, created once per isolate from safeHandle): published lists, slug and page-path lookups, updated_at, error log and not-found log. The engine's indexes start with tenant_id, which the sites' queries don't use, so busy sites could read whole tables and hit D1's CPU limit.

Added

  • Article schema: keywords from the post's visible tags (tags), never the focus keyphrase. AI Discovery page check warns when an article has no category or no tags.
  • SEO › AI Discovery tab: site checks (indexing, AI search / assistants / training policy, organisation, logo and profiles, default image and description, IndexNow, llms.txt) and a page check that reads the sitemap and opens each page like an AI crawler (no cookies, no JavaScript, served from the edge cache): reachable, indexable, canonical, title, description, share image, one h1, valid JSON-LD with article fields, enough text in the HTML.
  • SEO › Indexing › AI crawlers: three choices, AI search (on), AI assistants (on), AI training (off by default), written into robots.txt as a marked block plus a Content-Signal line. The bot list (src/plugins/ai-crawlers.ts, versioned) follows each operator's own docs: OpenAI, Anthropic, Google-Extended, Perplexity, Apple, Meta, Amazon, Common Crawl, ByteDance.
  • SEO structured data: posts can be BlogPosting or NewsArticle (articleType) and list their categories (articleSection via sections). Leave author out when the organisation wrote the post: the schema then names the organisation instead of a made-up person.
  • Settings › Cache: Keep sitemaps and feeds until content changes (on by default). Sitemaps, feeds, robots.txt and llms.txt stay at the edge until the next admin save instead of 60 minutes; clients still revalidate with the ETag.
  • SEO › Check: Calculate missing scores / Recalculate all. Imported or old items get their SEO and readability scores (the dots in the Content list) without opening each one: the browser runs the same analysis as the editor in batches of 40, updates go by id and keep updated_at (no IndexNow, no cache flush). The analysis now lives in one shared script (SEO_ANALYSE_CORE).

Fixed

  • IndexNow after a save read the whole documents table (no index on updated_at); it now creates idx_documents_updated_at once and reads only the last minute's changes.

BizzCMS 0.2.7

Choose a tag to compare

@idubravac idubravac released this 08 Oct 21:48

Added

  • Uploads made web-sized (src/image-upload.ts): JPEG/PNG/WebP wider than the maximum are scaled down and saved as WebP in the browser before upload (every admin upload). Settings › Images: on/off, maximum width (2000), quality (82). See docs/images.md.
  • Image hints (src/image-hints.ts): Media library images on public pages get their real width and height (read once from the file in R2, kept in KV), lazy images decoding="async", and the first image that is not lazy fetchpriority="high". Less layout shift, faster top image. Sites wrap their page handler with withImageHints(request, response, env.MEDIA_BUCKET, env.CACHE_KV).
  • Registration closed: /auth/register goes to sign-in and the register endpoints answer 404; administrators create accounts (Users).
  • SEO › General: X (Twitter) username; every page then carries twitter:site and twitter:creator.
  • IndexNow in the SEO plugin (SEO › Indexing, on by default): after every admin save the public addresses of the changed items go to IndexNow (Bing, Yandex, Seznam, Naver…); key file at /<key>.txt (generated, or paste your own); "Send all addresses to IndexNow now" from the sitemap; last 30 results listed. Never from local addresses or a hidden site. Sites wire seoIndexNowKey and seoIndexNowChanged (docs/seo.md).

BizzCMS 0.2.6

Choose a tag to compare

@idubravac idubravac released this 08 Oct 20:18

Fixed

  • The View on site eye (and the editor's View on Website) also works for extra collections such as a portfolio, using the site's routes.collections rule.

Added

  • Edge cache for public pages (src/edge-cache.ts): pages, lists, sitemaps and feeds are kept on Cloudflare (pages 5 minutes, sitemaps/feeds 60 minutes by default) and replaced at once on every admin save through a content version in KV. ETag and Last-Modified with 304 answers for browsers and crawlers; x-bizz-cache: HIT/MISS. Never for the admin, sign-in, API, files or signed-in people. Settings › Cache: on/off, both durations, "Clear the cache now". See docs/caching.md.

Changed

  • Sitemap choices: posts are split per section (Blog posts, News posts, each with its own sitemap, e.g. /sitemap-news.xml); "Other pages" is now "Pages built into the site, not in Content". /sitemap-posts.xml keeps working (all posts).

Added

  • Sidebar: sites can pin collections as their own entries with a count (setSidebarCollections([{ name: 'portfolio', label: 'Portfolio' }])), next to Blog and News.

Changed

  • Sidebar counts are kept in KV (CACHE_KV) and cleared when content is created, saved or deleted, so the sidebar never waits on a count.

Added

  • RSS feed (SEO plugin): /feed/ (all posts) and /<section>/feed/ (blog, news), RSS 2.0 like WordPress: featured image first (webfeedsFeaturedVisual) plus media:content, author, categories and tags, full text in content:encoded, "appeared first on" line; pages link to it. SEO › Indexing: on/off, number of posts, full text or summary. Sites call seoFeed(url, db).
  • SEO › Indexing › Include in sitemap: tick which parts go into /sitemap.xml (pages, posts, categories, tags, other pages, and extra collections a site adds with routes.collections, e.g. portfolio). Each settings tab now saves only its own fields.

Security

  • No technical errors shown to visitors. Any error, or a 5xx from the CMS engine (some of which included the raw database error), becomes a friendly page (or {"error":"Something went wrong","reference":"…"} for the API) with a short reference code. The details go to the console and to Settings › Error log (30 days, administrators only, search by reference). src/errors.ts; sites can give the page their own design with setErrorPage().

Added

  • Social Share plugin (Admin › Plugins › Social Share): a share bar for posts with copy link, LinkedIn, X, Facebook, WhatsApp, Pinterest, e-mail and the phone's share menu. Plain links with built-in icons: no third-party scripts or tracking. Pick the buttons and the label in the settings. Sites place it with await shareBar(db, url, title, image?) (empty while the plugin is off) and theme it with CSS on .bz-share / .bz-share-btn (--bz-share-c = brand colour). src/plugins/social-share.ts.
  • SEO › Redirects: a Not found list (last 90 days) of addresses that ended on "page not found", with hits, last visit and where visitors came from; Redirect… pre-fills a redirect, Dismiss removes it, and adding a redirect clears it. Sites call seoNotFound() where they return their 404 page.

Fixed

  • SEO: no "keywords" in the Article structured data. Search engines ignore it, and it showed anyone the keyphrases a post targets. Focus and related keyphrases stay in the editor's SEO analysis only. src/plugins/seo.ts.
  • SEO page and the editor's SEO card use the admin's standard tab bar (as on Settings) instead of their own underline tabs.
  • Sidebar jumped on every click. Blog and News were added by a script at the end of the page, after the sidebar was drawn. The server now puts them into the page (counts cached for a minute), so the sidebar is complete on the first paint.

BizzCMS 0.2.5

Choose a tag to compare

@idubravac idubravac released this 08 Oct 19:18

Changed

  • The CMS engine is now the bizzcms-core package (in vendor/, built from the upstream release; same code and version). All imports use bizzcms-core, and the admin's code examples show it too.

BizzCMS 0.2.4

Choose a tag to compare

@idubravac idubravac released this 08 Oct 18:40

Added

  • Images, tables, embeds and code in the visual editor. Images show as images, with an Image button in the toolbar (Media library) and double-click to edit the description. Tables, figures, YouTube and other embeds, code blocks and dividers are kept exactly as they are (shown read-only, edited in HTML). Loose text no longer breaks loading. src/lexical-blocks.ts.
  • HTML editor: every rich text field has a Visual | HTML | Preview switch. HTML edits the saved HTML directly; Visual is refused for HTML it would damage (images, tables, embeds, code blocks).

Fixed

  • Dashboard showed 0 media files and "0 B". Upstream still counts its old media table, which uploads no longer fill (they are media_asset documents). The Media Files card and Storage Usage now count the media documents. src/dashboard-media.ts (sites: add it to sync-core and wrap the upstream response with withMediaUsage).
  • Sidebar jumped when switching between Blog and News. The entries were only added after the counts loaded, so the menu shifted on every page. They now draw at once from the last known counts (kept in the browser) and the numbers refresh afterwards. src/sections.ts.
  • Editor could blank imported posts. Upstream's visual (Lexical) editor has no images, tables, embeds or code blocks: such HTML was dropped or the box stayed empty, and saving wrote that back. Content with those elements now opens in an HTML editor with a preview (nothing lost); if the visual editor loses text on load it switches too; emptying a box with text asks for confirmation, and the server refuses a save that would blank a post or page unless confirmed. src/content-guard.ts.

Added

  • Content list: an eye (View on site) before the edit button opens the published page in a new tab; the editor's View on Website uses the same address. Sites give their URL rules once with setPublicRoutes(SITEMAP_ROUTES). Drafts have no eye.
  • Sidebar: Blog and News entries under Workspace (after Content) with post counts, highlighted on their list; News only when the site has news posts.
  • Posts list divided by section: All posts | Blog | News tabs with counts above the list; filters, paging and "New Content" keep the section (a new post from News starts as News). src/sections.ts.
  • SEO plugin (Admin › SEO), modelled on Yoast SEO: SEO panel on pages, posts and categories with Google and share previews, focus keyphrase, SEO and readability analysis, Auto-fill SEO button, scores in the Content list; General settings (site name, title formats, organisation), Indexing (robots.txt, llms.txt, hide site), Redirects with CSV import, and a Check list. Sites get seoHead, sitemaps per type, robots.txt and structured data (Article, BreadcrumbList, WebSite, Organization). See docs/seo.md.
  • Categories collection (name, slug, section blog/news, description, SEO title and description).
  • Posts: Section (blog or news), Categories and Tags as searchable multiselects in the editor (categories filtered to the post's section, tags suggested from existing ones or added new), Author name / URL slug / website, Legacy ID and Legacy URL for imported posts. See docs/posts.md.

Changed

  • Node.js 24 LTS is now the minimum (engines >=24, .nvmrc); verified with 24.21.0.

BizzCMS 0.2.3

Choose a tag to compare

@idubravac idubravac released this 08 Oct 16:51

Added

  • Posts › Sponsored (checkbox), Sponsored by and Sponsored by link. Sponsored posts stay in the blog list with a "Sponsored" label and "Sponsored by …" on the post; links to other sites in their body get rel="sponsored noopener" automatically; "latest posts" teasers leave them out (NOT_SPONSORED). Helpers in src/sponsored.ts, see docs/posts.md.
  • sync:core now also copies the Posts collection and its helpers to the sites.
  • Posts › Featured image (picked from the Media library) and Featured image description (alt text). Sites show it on blog lists, the post page and as the social share image; posts without one keep the site's default image. Helper: src/featured-image.ts.
  • Plugin Google Analytics (Admin › Plugins): Measurement ID, consent banner on/off, banner text and policy link in a Settings tab. Public HTML pages get a cookie banner; Google Analytics loads only after Accept (Consent Mode v2, nothing sent before), the choice is remembered, Reject keeps it off. Never on admin, sign-in or API pages, never on localhost (?bizz-ga-preview shows it locally). Any element with data-cookie-settings reopens the banner. Install works around an upstream slug clash for code-registered plugins.

Security

  • Blocked upstream's unauthenticated POST /auth/seed-admin, which creates or resets an admin account with a password published in the SonicJS source. It now returns 404 on every BizzCMS site.

Fixed

  • Admin, sign-in and API pages could hang for about 20 seconds on the live site. SonicJS keeps start-up state as one shared promise per Worker isolate; when the request that started it was cancelled (tab closed, link clicked twice), that promise never settled and every later request on the isolate waited for it. SonicJS calls now always run to completion (src/upstream.ts, ctx.waitUntil).

Changed

  • Content editor: "Preview Content" became "View on Website" and opens the published page in a new tab (pages by path, posts at /blog/) instead of upstream's bare preview page.
  • bizzcms.com is live: README, package.json (homepage, repository, issues), the API description's contact link and the GitHub repository website now point to https://bizzcms.com.
  • Wordmark in Inter Tight regular in the admin and on sign-in pages, like the website; the version badge uses the theme colours in light and dark.
  • Admin footer and README: "Made with ♥ by Ingenium" (links to ingenium.software).
  • Dark mode: the page body and the shell behind the sidebar use the dark teal canvas instead of near-black.
  • Sign-in pages: the logo links to the website's home page on every page (login, register, reset password, invitation, two-step); two-step verification now shows the logo.
  • Dashboard: the requests chart uses the theme (dark teal #086568 on light, lime on dark, follows the switch); storage numbers no longer lime on white; side cards line up with the chart; a plain empty state replaces the "System ·" placeholder; dark cards use the dark teal surfaces on every admin page.