tomvondracek/bolt-discussion 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

tomvondracek/bolt-discussion

Composer 安装命令:

composer require tomvondracek/bolt-discussion

包简介

📦 Pluggable, themeable discussion / comments module for Bolt CMS 6 (replies, reactions, async submit, REST polling).

README 文档

README

A pluggable, themeable discussion / comments module for Bolt CMS 6.

  • Anyone (logged-in or anonymous) can post comments
  • One-level threaded replies (no deep nesting)
  • Emoji reactions (configurable set, deduped per visitor)
  • PHP-rendered initial page to avoid layout shift, then async submit and REST polling for live updates
  • Editor-level Bolt users (ROLE_EDITOR) can delete from the frontend and moderate in the Bolt admin
  • Decoupled from contenttypes: a discussion is identified by an arbitrary string reference, so you can place many independent discussions anywhere
  • Fully themeable per project via --bd-* CSS custom properties
  • Honeypot + optional spam regex + IP rate-limiting; auto or queue moderation

Requirements

  • Bolt CMS ^6.0, PHP >=8.2
  • Node >=22.13 (to build the frontend assets with Symfony Encore)

Installation

  1. Require the package (published, or as a local Composer path repository):

    composer require tomvondracek/bolt-discussion
  2. Build the frontend assets (shipped source builds to public/build/):

    cd vendor/tomvondracek/bolt-discussion
    npm install && npm run build
  3. Register the entity mapping. Extensions aren't bundles, so add this under doctrine.orm.mappings in your project's config/packages/doctrine.yaml:

    BoltDiscussion:
      is_bundle: false
      type: attribute
      dir: '%kernel.project_dir%/vendor/tomvondracek/bolt-discussion/src/Entity'
      prefix: 'BoltDiscussion\Entity'
      alias: BoltDiscussion
  4. Copy routes/services and create the tables:

    bin/console extensions:configure
    bin/console doctrine:migrations:diff        # generates the create-tables migration
    bin/console doctrine:migrations:migrate
    bin/console cache:clear

Usage

Place a discussion anywhere in a frontend template. The reference is any string that scopes an independent thread:

{{ discussion('record-' ~ record.id, { title: 'Comments' }) }}

{# show a count somewhere else #}
{{ discussion_count('record-' ~ record.id) }} comments

Per-instance copy

The second argument is an options map, so each discussion can carry its own composer text (handy when one page hosts several). Each option falls back to the translated default, and you translate it yourself — pass a literal, or your own |trans call:

{{ discussion('event-2027', {
    title: 'Lineup ideas',
    namePlaceholder: 'name.placeholder'|trans,
    commentPlaceholder: 'What should we book?',
    replyPlaceholder: 'Write a reply…',
    submitLabel: 'Send it'
}) }}
Option Overrides
title Heading above the thread
namePlaceholder The name field placeholder
commentPlaceholder The comment box placeholder
replyPlaceholder The reply box placeholder
submitLabel The post-comment button label

The extension injects its CSS/JS only on pages that actually contain a mount. The initial comment page and composer are rendered during the PHP request, so the widget has its final layout before JavaScript runs. JavaScript hydrates that markup and is then used only for interactions, older pages, and live polling.

Configuration

Edit config/extensions/boltdiscussion.yaml (created on first run):

Key Default Description
moderation auto auto publishes immediately; queue holds anonymous comments as pending (logged-in users always auto-publish)
poll_interval 10000 Polling interval in ms; 0 disables polling
page_size 10 Root comments per page (newest first); "Load more" reveals older ones. Clamped to 1..100
reactions_enabled true Toggle reactions
reactions ['👍','❤️','😂','🎉','😮'] Allowed reaction emoji
replies_enabled true Toggle one-level replies
max_length 2000 Max comment length
require_name true Require a name from anonymous posters
spam_regex '' If set, matching bodies are stored as spam
rate_limit_seconds 10 Min seconds between anonymous posts from one IP; 0 disables (logged-in users are never throttled)

Theming

The widget is designed to be re-skinned without touching the extension. Every visual value resolves to a --bd-* custom property declared on .bolt-discussion, covering colour, type, radii, spacing, shadow, the per-author avatars, and the reply-thread connector. There are two ways to customize:

1. Re-declare variables (the usual path) — map them onto your design tokens:

.bolt-discussion.bolt-discussion {
    /* colour */
    --bd-color-accent: var(--color-brand);
    --bd-color-surface: var(--color-white);
    --bd-color-border: var(--color-gray-200);
    /* type & shape */
    --bd-font: var(--font-body);
    --bd-radius: 12px;
    --bd-radius-pill: 999px;
    /* avatars (hue is set per-author; tune saturation/lightness/shape) */
    --bd-avatar-radius: 50%;
    --bd-avatar-sat: 58%;
    --bd-avatar-light: 48%;
    /* reply connector */
    --bd-thread-line: var(--color-gray-200);
}

(The doubled .bolt-discussion selector raises specificity so your overrides win regardless of stylesheet load order.)

2. Override BEM classes for structural or typographic flourishes, e.g.:

.bolt-discussion .bolt-discussion__author { text-transform: uppercase; }
.bolt-discussion .bolt-discussion__avatar { box-shadow: 0 0 0 2px var(--color-brand); }

See the rockfest theme (public/theme/rockfest/css/discussion-theme.css) for a complete "gig-poster" example combining both. You can also override templates/mount.html.twig by placing a same-named template in your active theme.

Built-in UX

Modern thread UI out of the box: top composer with an auto-growing field, colour-coded initial avatars, locale-aware relative timestamps (Intl.RelativeTimeFormat), reaction chips with a emoji picker, and collapsible reply threads with a connector line. Respects prefers-reduced-motion and ships visible keyboard focus.

Returning visitors

Anonymous visitors are remembered across visits without any login:

  • Name — the last name posted is stored in localStorage (bolt-discussion:name) and prefilled into the composer and reply forms, so people don't retype it.
  • Reaction state — whether you already reacted to a comment ("mine") is tracked per visitor. The identity lives in a year-long bd_visitor cookie and a localStorage id (bolt-discussion:vid) sent as an X-BD-Visitor header, so it survives even if cookies are cleared. Anonymous ids are validated and namespaced, so they can never impersonate a logged-in user's reactions.

All of this is per-browser and needs no personal data or account.

Admin

A Discussion entry appears in the Bolt admin sidebar (/bolt/extension/discussion), listing discussions grouped by reference with per-thread approve / delete / mark-spam.

Translations

All user-facing text (frontend widget, validation/API errors, and the admin screens) is translated via the bolt_discussion translation domain. Catalogs ship for English, Czech, German, Polish and Dutch in translations/ (bolt_discussion.<locale>.yaml), using the English source string as the key.

extensions:configure registers the path automatically (it copies framework.translator.paths into config/packages/extension_bolt-discussion.yaml). Frontend JS strings are translated server-side and passed to the widget via a data-i18n attribute. To add a locale, drop a bolt_discussion.<locale>.yaml file in translations/ and clear the cache.

统计信息

  • 总下载量: 1
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-23

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固